<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.0.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/wang-cheng/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/wang-cheng/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/wang-cheng/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/wang-cheng/images/logo.svg" color="#222">

<link rel="stylesheet" href="/wang-cheng/css/main.css">


<link rel="stylesheet" href="/wang-cheng/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"cheng-wang123.gitee.io","root":"/wang-cheng/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
<meta property="og:type" content="website">
<meta property="og:title" content="诚の博客">
<meta property="og:url" content="https://cheng-wang123.gitee.io/wang-cheng/page/2/index.html">
<meta property="og:site_name" content="诚の博客">
<meta property="og:description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="王诚">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://cheng-wang123.gitee.io/wang-cheng/page/2/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : true,
    isPost : false,
    lang   : 'zh-CN'
  };
</script>

  <title>诚の博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/wang-cheng/atom.xml" title="诚の博客" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/wang-cheng/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">诚の博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">记录学习中的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/wang-cheng/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/wang-cheng/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/wang-cheng/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/wang-cheng/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content index posts-expand">
            
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/04/05/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%BA%94/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/04/05/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%BA%94/" class="post-title-link" itemprop="url">算法笔记(五)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-04-05 12:53:28" itemprop="dateCreated datePublished" datetime="2022-04-05T12:53:28+08:00">2022-04-05</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-07 17:45:51" itemprop="dateModified" datetime="2022-04-07T17:45:51+08:00">2022-04-07</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="树形dp套路"><a href="#树形dp套路" class="headerlink" title="树形dp套路"></a><strong>树形dp套路</strong></h2><p>树形套路使用前提:</p>
<p>如果题目求解目标是S规则，则求解流程可以定成以每一个节点为头节点的子树在S规则下的每一个答案，并且最终答案一定在其中。</p>
<p>题目；二叉树节点间的最大距离问题</p>
<p>从二叉树的节点a出发，可以向上或者向下走，但沿途的节点只能经过一次，到达节点b时路径上的节点个数叫做a到b的距离，那么二叉树任何两个节点之间都有距离，求整棵树上的最大距离</p>
<p>经验：这种题一般情况下都会分成两类</p>
<ol>
<li><p>根节点不参与组成最大距离的路径 左边的最大距离maxdistance、右边的最大距离maxdistance</p>
</li>
<li><p>根节点参与组成最大距离的路径  左树的最大高度h+右树最大高度h+1</p>
</li>
</ol>
<figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">public</span> static <span class="type">int</span> maxDistance(Node node)&#123;</span><br><span class="line">    <span class="keyword">return</span> process(node).maxDistance;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> static <span class="keyword">class</span> <span class="keyword">Info</span> &#123;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> maxDistance;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> height;</span><br><span class="line">    <span class="built_in">public</span> <span class="keyword">Info</span>(<span class="type">int</span> m, <span class="type">int</span> h) &#123;</span><br><span class="line">        maxDistance = m;</span><br><span class="line">        height = h;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> static <span class="keyword">Info</span> process(Node x) &#123;</span><br><span class="line">    <span class="keyword">if</span> (x == <span class="keyword">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="built_in">new</span> <span class="keyword">Info</span>(<span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">Info</span> leftInfo = process(x.left);</span><br><span class="line">    <span class="keyword">Info</span> rightInfo = process(x.right);</span><br><span class="line">    <span class="type">int</span> height = Math.max(leftInfo.height, rightInfo.height) + <span class="number">1</span>;</span><br><span class="line">    <span class="type">int</span> p1 = leftInfo.maxDistance;</span><br><span class="line">    <span class="type">int</span> p2 = rightInfo.maxDistance;</span><br><span class="line">    <span class="type">int</span> p3 = leftInfo.height + rightInfo.height + <span class="number">1</span>;</span><br><span class="line">    <span class="type">int</span> maxDistance = Math.max(Math.max(p1, p2), p3);</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">new</span> <span class="keyword">Info</span>(maxDistance, height);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>树形dp套路第一步:</p>
<p>以某个节点X为头节点的子树中，分析答案有哪些可能性，并且这种分析是以X的左子树、X的右子树和X整棵树的角度来考虑可能性的</p>
<p>树形dp套路第二步:</p>
<p>根据第一步的可能性分析，列出所有需要的信息</p>
<p>树形dp套路第三步:</p>
<p>合并第二步的信息，对左树和右树提出同样的要求，并写出信息结构</p>
<p>树形dp套路第四步:</p>
<p>设计递归函数，递归函数是处理以X为头节点的情况下的答案。包括设计递归的basecase，默认直接得到左树和右树的所有信息，以及把可能性做整合，并且要返回第三步的信息结构</p>
<h2 id="Morris遍历"><a href="#Morris遍历" class="headerlink" title="Morris遍历"></a><strong>Morris遍历</strong></h2><p>一种遍历二叉树的方式，并且时间复杂度O(N),额外空间复杂度O(1)。</p>
<p>通过利用原树中大量空闲指针的方式，达到节省空间的目的</p>
<h3 id="Morris遍历细节"><a href="#Morris遍历细节" class="headerlink" title="Morris遍历细节"></a><strong>Morris遍历细节</strong></h3><p>假设来到当前节点cur，开始时cur来到头节点位置</p>
<ol>
<li><p>如果cur没有左孩子，cur向右移动(cur = cur.right)</p>
</li>
<li><p>如果cur有左孩子，找到左子树上最右的节点mostRight</p>
<ol>
<li><p>如果mostRight的右指针指向空，让其指向cur，然后cur向左移动(cur = cur.left)</p>
</li>
<li><p>如果mostRight的右指针指向cur，让其指向null，然后cur向右移动(cur = cur.right)</p>
</li>
</ol>
</li>
<li><p>cur为空时遍历停止</p>
</li>
</ol>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">morris</span><span class="params">(Node head)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (head == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">Node</span> <span class="variable">cur</span> <span class="operator">=</span> head;</span><br><span class="line">    <span class="type">Node</span> <span class="variable">mostRight</span> <span class="operator">=</span> <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">while</span> (cur != <span class="literal">null</span>) &#123;</span><br><span class="line">        mostRight = cur.left;</span><br><span class="line">        <span class="keyword">if</span> (mostRight != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">while</span> (mostRight.right != <span class="literal">null</span> &amp;&amp; mostRight.right != cur) &#123;</span><br><span class="line">                mostRight = mostRight.right;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (mostRight.right == <span class="literal">null</span>) &#123;</span><br><span class="line">                mostRight.right = cur;</span><br><span class="line">                cur = cur.left;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                mostRight.right = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        cur = cur.right;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="Morris遍历之先序遍历"><a href="#Morris遍历之先序遍历" class="headerlink" title="Morris遍历之先序遍历"></a><strong>Morris遍历之先序遍历</strong></h3><p>如果一个节点只到达一次，直接打印</p>
<p>如果一个节点能够到达两次，第一次打印</p>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">morrisPre</span>(<span class="params">Node head</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (head == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Node cur = head;</span><br><span class="line">    Node mostRight = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">while</span> (cur != <span class="literal">null</span>) &#123;</span><br><span class="line">        mostRight = cur.left;</span><br><span class="line">        <span class="keyword">if</span> (mostRight != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">while</span> (mostRight.right != <span class="literal">null</span> &amp;&amp; mostRight.right != cur) &#123;</span><br><span class="line">                mostRight = mostRight.right;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (mostRight.right == <span class="literal">null</span>) &#123;<span class="comment">//这是第一次来到这个节点</span></span><br><span class="line">                System.<span class="keyword">out</span>.print(cur.<span class="keyword">value</span> + <span class="string">&quot; &quot;</span>);</span><br><span class="line">                mostRight.right = cur;</span><br><span class="line">                cur = cur.left;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;<span class="comment">//第二次来到这个节点</span></span><br><span class="line">                mostRight.right = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;<span class="comment">//没有左子树的情况</span></span><br><span class="line">            System.<span class="keyword">out</span>.print(cur.<span class="keyword">value</span> + <span class="string">&quot; &quot;</span>);</span><br><span class="line">        &#125;</span><br><span class="line">        cur = cur.right;</span><br><span class="line">    &#125;</span><br><span class="line">    System.<span class="keyword">out</span>.println();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="Morris遍历之中序遍历"><a href="#Morris遍历之中序遍历" class="headerlink" title="Morris遍历之中序遍历"></a><strong>Morris遍历之中序遍历</strong></h3><p>如果一个节点只到达一次，直接打印</p>
<p>如果一个节点能够到达两次，第二次打印<br><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">morrisIn</span>(<span class="params">Node head</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (head == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Node cur = head;</span><br><span class="line">    Node mostRight = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">while</span> (cur != <span class="literal">null</span>) &#123;</span><br><span class="line">        mostRight = cur.left;</span><br><span class="line">        <span class="keyword">if</span> (mostRight != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">while</span> (mostRight.right != <span class="literal">null</span> &amp;&amp; mostRight.right != cur) &#123;</span><br><span class="line">                mostRight = mostRight.right;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (mostRight.right == <span class="literal">null</span>) &#123;</span><br><span class="line">                mostRight.right = cur;</span><br><span class="line">                cur = cur.left;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                mostRight.right = <span class="literal">null</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        System.<span class="keyword">out</span>.print(cur.<span class="keyword">value</span> + <span class="string">&quot; &quot;</span>);</span><br><span class="line">        cur = cur.right;</span><br><span class="line">    &#125;</span><br><span class="line">    System.<span class="keyword">out</span>.println();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h3 id="Morris遍历之后序遍历"><a href="#Morris遍历之后序遍历" class="headerlink" title="Morris遍历之后序遍历"></a><strong>Morris遍历之后序遍历</strong></h3><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="title function_">morrisPos</span>(<span class="params">Node head</span>) &#123;</span><br><span class="line">    <span class="keyword">if</span> (head == <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title class_">Node</span> cur = head;</span><br><span class="line">    <span class="title class_">Node</span> mostRight = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">while</span> (cur != <span class="literal">null</span>) &#123;</span><br><span class="line">        mostRight = cur.<span class="property">left</span>;</span><br><span class="line">        <span class="keyword">if</span> (mostRight != <span class="literal">null</span>) &#123;</span><br><span class="line">            <span class="keyword">while</span> (mostRight.<span class="property">right</span> != <span class="literal">null</span> &amp;&amp; mostRight.<span class="property">right</span> != cur) &#123;</span><br><span class="line">                mostRight = mostRight.<span class="property">right</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span> (mostRight.<span class="property">right</span> == <span class="literal">null</span>) &#123;</span><br><span class="line">                mostRight.<span class="property">right</span> = cur;</span><br><span class="line">                cur = cur.<span class="property">left</span>;</span><br><span class="line">                <span class="keyword">continue</span>;</span><br><span class="line">            &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">                mostRight.<span class="property">right</span> = <span class="literal">null</span>;</span><br><span class="line">                <span class="title function_">printEdge</span>(cur.<span class="property">left</span>);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        cur = cur.<span class="property">right</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">printEdge</span>(head);</span><br><span class="line">    <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">println</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="title function_">printEdge</span>(<span class="params">Node head</span>) &#123;</span><br><span class="line">    <span class="title class_">Node</span> tail = <span class="title function_">reverseEdge</span>(head);</span><br><span class="line">    <span class="title class_">Node</span> cur = tail;</span><br><span class="line">    <span class="keyword">while</span> (cur != <span class="literal">null</span>) &#123;</span><br><span class="line">        <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">print</span>(cur.<span class="property">value</span> + <span class="string">&quot; &quot;</span>);</span><br><span class="line">        cur = cur.<span class="property">right</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title function_">reverseEdge</span>(tail);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="title class_">Node</span> <span class="title function_">reverseEdge</span>(<span class="params">Node <span class="keyword">from</span></span>) &#123;</span><br><span class="line">    <span class="title class_">Node</span> pre = <span class="literal">null</span>;</span><br><span class="line">    <span class="title class_">Node</span> next = <span class="literal">null</span>;</span><br><span class="line">    <span class="keyword">while</span> (<span class="keyword">from</span> != <span class="literal">null</span>) &#123;</span><br><span class="line">        next = <span class="keyword">from</span>.<span class="property">right</span>;</span><br><span class="line">        <span class="keyword">from</span>.<span class="property">right</span> = pre;</span><br><span class="line">        pre = <span class="keyword">from</span>;</span><br><span class="line">        <span class="keyword">from</span> = next;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> pre;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="大数据题目的解题技巧"><a href="#大数据题目的解题技巧" class="headerlink" title="大数据题目的解题技巧"></a><strong>大数据题目的解题技巧</strong></h2><ol>
<li><p>哈希函数可以把数据按照种类分流</p>
</li>
<li><p>布隆过滤器用于集合的建立与查询，并可以节省大量空间</p>
</li>
<li><p>一致性哈希解决数据服务器的负载管理问题</p>
</li>
<li><p>利用并查集结构做岛问题的并行计算</p>
</li>
<li><p>位图(用一个比特就能表示一个数出现或者没出现过)解决某一范围上数字的出现情况，并可以节省大量空间</p>
</li>
<li><p>利用分段思想、并进一步节省大量空间</p>
</li>
<li><p>利用堆、外排序来做多个处理单元的结果合并</p>
</li>
</ol>
<h2 id="位图解决类型的题目"><a href="#位图解决类型的题目" class="headerlink" title="位图解决类型的题目"></a><strong>位图解决类型的题目</strong></h2><p>32位无符号整数的范围是0~4294967295(2^32-1),现在有一个正好包含40亿个无符号整数的文件，所以在整个范围中必然存在没出现过的数。可以使用最多1GB的内存，怎么找到所有未出现过的数？</p>
<p>【进阶】内存限制位为10MB，但是只用找到一个没出现过的数即可</p>
<p>【再进阶】假如只能申请几个有限变量，怎么找到一个没出现过的数</p>
<p>分段</p>
<hr>
<p>有一个包含100亿个URL的大文件，假设每个URL占用64B，请找出其中所有重复的URL</p>
<p>【补充】某搜索公司一天的用户搜索词汇是海量的，请设计一种求出每天热门Top100词汇的可行方法</p>
<p>布隆过滤器、哈希分流</p>
<p>大根堆实现补充的问题</p>
<h2 id="题目分类"><a href="#题目分类" class="headerlink" title="题目分类"></a><strong>题目分类</strong></h2><ol>
<li><p>业务为主的题目</p>
<ul>
<li>业务为主的题目，主要核心思想是它业务本身，根据业务逻辑做出算法逻辑</li>
</ul>
</li>
<li><p>技巧为主的题目</p>
<ul>
<li>业务对最后的算法思想不是多重要，反而是你已经熟悉的技巧比如红黑树等成熟的数据结构，对最后算法起到根本作用。</li>
</ul>
</li>
</ol>
<p>笔试阶段：</p>
<p>业务为主的题会占到55%，技巧为主的题会占到45%</p>
<p>面试阶段：</p>
<p>业务为主的题会占到30%，技巧为主的题会占到70%</p>
<h2 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a><strong>堆排序</strong></h2><h3 id="heapInsert"><a href="#heapInsert" class="headerlink" title="heapInsert"></a><strong>heapInsert</strong></h3><figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> heapInsert(<span class="built_in">int</span>[] arr,<span class="built_in">int</span> <span class="keyword">index</span>)&#123;</span><br><span class="line">    <span class="keyword">while</span>(arr[<span class="keyword">index</span>] &gt; arr[(<span class="keyword">index</span><span class="number">-1</span>)/<span class="number">2</span>])&#123;</span><br><span class="line">        swap(arr,<span class="keyword">index</span>,(<span class="keyword">index</span><span class="number">-1</span>)/<span class="number">2</span>);</span><br><span class="line">        <span class="keyword">index</span> = (<span class="keyword">index</span><span class="number">-1</span>)/<span class="number">2</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="heapify"><a href="#heapify" class="headerlink" title="heapify"></a><strong>heapify</strong></h3><figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> heapify(<span class="built_in">int</span>[] arr,<span class="built_in">int</span> <span class="keyword">index</span>,<span class="built_in">int</span> heapSize)&#123;</span><br><span class="line">    <span class="built_in">int</span> left = <span class="keyword">index</span>*<span class="number">2</span> + <span class="number">1</span>;<span class="comment">//左孩子的下标</span></span><br><span class="line">    <span class="keyword">while</span>(left &lt; heapSize)&#123;<span class="comment">//下方还有孩子的时候</span></span><br><span class="line">        <span class="comment">//两个孩子中，谁的值大，把下标给largest</span></span><br><span class="line">        <span class="built_in">int</span> largest = left+<span class="number">1</span> &lt; heapSize &amp;&amp; arr[left+<span class="number">1</span>] &gt; arr[left] ? left + <span class="number">1</span> : left;</span><br><span class="line">        <span class="comment">//父和孩子之间，谁的值大，把下标给largest</span></span><br><span class="line">        largest = arr[largest] &gt; arr[<span class="keyword">index</span>] ? largest : <span class="keyword">index</span>;</span><br><span class="line">        <span class="keyword">if</span>(largest == <span class="keyword">index</span>)&#123;</span><br><span class="line">            <span class="keyword">break</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        swap(arr,largest,<span class="keyword">index</span>);</span><br><span class="line">        <span class="keyword">index</span> = largest;</span><br><span class="line">        left = <span class="keyword">index</span> * <span class="number">2</span> + <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> swap(<span class="built_in">int</span>[] arr,<span class="built_in">int</span> i,<span class="built_in">int</span> j)&#123;</span><br><span class="line">    <span class="built_in">int</span> temp = arr[i];</span><br><span class="line">    arr[i] = arr[j];</span><br><span class="line">    arr[j] = arr[i];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="两个栈拼出一个队列和两个队列拼出一个栈"><a href="#两个栈拼出一个队列和两个队列拼出一个栈" class="headerlink" title="两个栈拼出一个队列和两个队列拼出一个栈"></a><strong>两个栈拼出一个队列和两个队列拼出一个栈</strong></h2><p>图的深度优先遍历，让你用队列做————两个栈拼一个队列</p>
<p>图的宽度优先遍历，让你用栈做————两个栈拼一个队列</p>
<h2 id="动态规划的空间压缩技巧"><a href="#动态规划的空间压缩技巧" class="headerlink" title="动态规划的空间压缩技巧"></a><strong>动态规划的空间压缩技巧</strong></h2><p>给你一个二维数组matrix，其中每个数都是正数，要求从左上角走到右下角。每一步只能向右或者向下，沿途经过的数字要累加起来。最后请返回最小的路径和。</p>
<h2 id="给定一个数组arr，如果通过调整可以做到arr中任意两个相邻的数组相乘是4的倍数，返回true，如果不能返回false"><a href="#给定一个数组arr，如果通过调整可以做到arr中任意两个相邻的数组相乘是4的倍数，返回true，如果不能返回false" class="headerlink" title="给定一个数组arr，如果通过调整可以做到arr中任意两个相邻的数组相乘是4的倍数，返回true，如果不能返回false"></a><strong>给定一个数组arr，如果通过调整可以做到arr中任意两个相邻的数组相乘是4的倍数，返回true，如果不能返回false</strong></h2><p>遍历数组，统计三类数的个数</p>
<ol>
<li><p>奇数 a个</p>
</li>
<li><p>偶数</p>
<ul>
<li><p>只含有一个2因子的数 b个</p>
</li>
<li><p>包含4因子的数 c个</p>
</li>
</ul>
</li>
</ol>
<p>第一种情况，b == 0时， </p>
<pre><code>+ 如果a = 1，c &gt;= 1
+ 如果a &gt; 1，c &gt;= a-1
</code></pre><p>第二种情况，b != 0时，先把b类数摆在一起，</p>
<pre><code>+ 如果a = 0，c &gt;= 0
+ 如果a = 1,c &gt;= 1
+ 如果a &gt; 1,c &gt;= a
</code></pre>
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/04/02/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E5%9B%9B/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/04/02/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E5%9B%9B/" class="post-title-link" itemprop="url">算法笔记(四)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-04-02 19:26:21" itemprop="dateCreated datePublished" datetime="2022-04-02T19:26:21+08:00">2022-04-02</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-26 16:04:15" itemprop="dateModified" datetime="2022-04-26T16:04:15+08:00">2022-04-26</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="哈希函数与哈希表等"><a href="#哈希函数与哈希表等" class="headerlink" title="哈希函数与哈希表等"></a><strong>哈希函数与哈希表等</strong></h1><h2 id="哈希结构"><a href="#哈希结构" class="headerlink" title="哈希结构"></a><strong>哈希结构</strong></h2><ol>
<li><p>无限个输入、有限个输出</p>
<ul>
<li>例如：MD5加密算法就是采用哈希底层的算法实现， MD5的取值范围为0~2^64-1。所以可以输入任何的对象，但它只会给你返回给一个有限值</li>
</ul>
</li>
<li><p>相同的输入，一定会有一个相同的输出。也就是说你输入相同的对象，输出的哈希值一定相同</p>
</li>
<li><p>不同的输入、可能会输出相同的值。因为哈希值是有限的，输入两个不同的对象也可能获得相同的值。这种情况被称为哈希碰撞(可能性极低)</p>
</li>
<li><p>假设将哈希函数的输出范围看作一个域S。每输入一个值，都可以看作是在S上的一个点。</p>
<ul>
<li>哈希函数最重要的性质是：它可以将这些点均匀的分布在域S上，使得它的均匀性和离散型都能得到保证<ul>
<li>离散型:不同的输入，离散到S上的位置是没规律的。离散性越好，哈希函数越好。</li>
</ul>
</li>
</ul>
</li>
</ol>
<h2 id="哈希表的实现"><a href="#哈希表的实现" class="headerlink" title="哈希表的实现"></a><strong>哈希表的实现</strong></h2><h3 id="哈希表是如何将时间复杂度逼近为O-1-的"><a href="#哈希表是如何将时间复杂度逼近为O-1-的" class="headerlink" title="哈希表是如何将时间复杂度逼近为O(1)的"></a><strong>哈希表是如何将时间复杂度逼近为O(1)的</strong></h3><p>假设现在哈希表的长度为17</p>
<p>再假设现在向哈希表中放入一个对象，假设为’abc’，对应值为34。</p>
<ol>
<li><p>哈希表对’abc’调用一个哈希函数，得出一个值out1</p>
</li>
<li><p>out1%17，会得到一个具体的值，这个值在哈希表中具有具体的位置。假设为13。</p>
</li>
<li><p>找到哈希表中下标为13的位置，在这个位置串一张单链表，单链表节点为’abc’,伴随值为34.</p>
</li>
<li><p>假设又放入一个对象，调用完哈希函数，取完模之后的的值也是13，就在单链表的尾部再串一个节点</p>
</li>
</ol>
<p>问题:如果加入大量对象，那么哈希表中的链就会很长。怎么办呢？</p>
<p><strong>哈希表减小时间复杂度的第一个技术：利用哈希函数与链表相结合的方式达到目标</strong></p>
<p>在哈希表中，定义一个变量，统计每个数组中链表的长度，如果长度超过了6，就触发扩容逻辑(当哈希表的链表长度过长，增删改查的速度也会随之降低，一般哈希表增上改查的时间复杂度是小于O(logN))。因为哈希函数具有离散性和均匀性，所以其他链表的长度也接近于6了。</p>
<p>触发扩容机制后，会新建一张哈希表，如果之前哈希表的长度为17，新建的这张表的长度则为34。然后原先表中的元素会重新算一遍哈希值，然后放到新表中。</p>
<p>时间复杂度的分析：找一个在哈希表中的对象，只需要算它的哈希函数，所以时间复杂度是O(1)，但这个复杂度的常识很大，取模的时间复杂度也是O(1)。然后去数组中去找，如果我的链表的长度为k，那么我的时间复杂度就是O(K),如果保证这个链表的长度不会过长，那么它就可以看作是O(1)。但是链表过长的时候是会触发扩容的，扩容的代价怎么算？</p>
<p>扩容代价的计算：如果我向哈希表中加入了N个对象，则会触发logN次扩容(实际中远远小于logN,但也只是在常数级别小于logN)。每次扩容，都需要将原来哈希表中的N个对象重新计算哈希值重新存入新哈希表，所以它的时间复杂度为O(N)。则总的代价为O(N*logN)。而这是计算的一共扩容logN次的代价，所以每一次扩容的代价为O(logN)。</p>
<p>但是为什么说哈希表在使用的时候，时间复杂度一般为O(1)呢？因为哈希表可以将K定义得很长，也不会很大的影响我的时间复杂度O(K)，但是可以极大的减小我的扩容代价。所以这个O(logN)就成为了一个特别小的常数的一个数，则这个O(logN)就会慢慢逼近O(1)。</p>
<p><strong>哈希表减小时间复杂度的第二个技术:离线扩容</strong></p>
<p>JVM在使用哈希表的时候，在不影响原先表使用的情况下，可以新建一张哈希表，当原表存入对象过多，可以把引用对象切换到新表上。这样可以在不占用用户时间的情况下，实现扩容，再次将时间复杂度变得很低。</p>
<p><strong>所以，哈希表的增删改查虽然在理论上来说时间复杂度是O(logN)，但是在实际中是可以看作O(1)的</strong></p>
<p>哈希表在Java中还有所改进，将链表改为了二叉树</p>
<h2 id="详解布隆过滤器"><a href="#详解布隆过滤器" class="headerlink" title="详解布隆过滤器"></a><strong>详解布隆过滤器</strong></h2><h3 id="字节-Byte-与比特-bit-之间的关系"><a href="#字节-Byte-与比特-bit-之间的关系" class="headerlink" title="字节(Byte)与比特(bit)之间的关系"></a><strong>字节(Byte)与比特(bit)之间的关系</strong></h3><p>计算机存储单位一般用bit、B、KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB……来表示，它们之间的关系是</p>
<p>位 bit (比特)(Binary Digits)：存放一位二进制数，即 0 或 1，最小的存储单位</p>
<p>字节byte：8个二进制位为一个字节(B)，最常用的单位。</p>
<p>1 Byte（B） = 8 bit</p>
<p>1 Kilo Byte（KB） = 1024B</p>
<p>1 Mega Byte（MB） = 1024 KB</p>
<p>1 Giga Byte （GB）= 1024 MB</p>
<p>1 Tera Byte（TB）= 1024 GB</p>
<p>1 Peta Byte（PB） = 1024 TB</p>
<h3 id="布隆过滤器的原理"><a href="#布隆过滤器的原理" class="headerlink" title="布隆过滤器的原理"></a><strong>布隆过滤器的原理</strong></h3><p>0~m-1，长度为m的bit类型的结构，实际占用空间为m/8个字节(电脑统计空间都用字节)的内存。</p>
<p>每个url，调用哈希函数，算出k个哈希值，模上一个数m，得到k个位置。将这k个位置标记下来。</p>
<p>当去查询这个黑名单，通过url算出哈希值，模上m，得到k位置，查看这k个位置有没有被标记，如果这个url是黑名单里的数，那么这个url一定被标记过</p>
<p>失误率是由m和k决定的。如果m过小，数据量过大，经过上面的操作后，整个结构可能都变成被标记的，那么无论查哪个url都是黑名单里的url。</p>
<p>k可以形象的看作是采集指纹，k越大，得到的位置越多，url越精确，不同的url算出在同一个位置的概率较小，也可以降低失误率。</p>
<p>可以先确定m需要定多大，然后根据已经确定的参数计算出有多少个哈希函数是合适的。</p>
<h3 id="面试中聊到布隆过滤器"><a href="#面试中聊到布隆过滤器" class="headerlink" title="面试中聊到布隆过滤器"></a><strong>面试中聊到布隆过滤器</strong></h3><p>设计过滤器，只需要确定是不是这个模型(集合结构，没有删除行为，类似黑名单查询的)、有没有失误率</p>
<ol>
<li><p>在跟面试官聊的时候，要回答什么时候可以用过滤器—&gt;类似于黑名单，而且没有删除行为的</p>
</li>
<li><p>问面试官：这个系统允不允许有失误率  如果面试官说允许，那么他考你的就是过滤器。</p>
</li>
<li><p>既然允许，那么就需要问他，他的失误率预期是多少</p>
</li>
</ol>
<p>注意:布隆过滤器只和样本量、失误率两个参数有关。与单一样本的大小没有关系。</p>
<script type="math/tex; mode=display">公式: m = -\frac{n*lnp}{(ln2)^2} \quad</script><p>n = 100亿、p = 0.0001带进去，算出m的值，算出来的数除以8才是实际占用的内存</p>
<p>这个结果大约26G</p>
<script type="math/tex; mode=display">公式: k = 0.7* \frac{m}{n} \quad</script><p>k的值可能是小数，向上取整(取整后为k(真))。k为需要的哈希函数个数。</p>
<p>这里需要注意:上面算出来的内存为26G，这个内存是达到这个失误率的最小内存了，如果我的内存可以更大一些m(真)，那么我的失误率将会再次降低，而要求这个失误率为多少，也会公式：</p>
<script type="math/tex; mode=display">p(真)=(1-{\rm e}^x)^{k(真)}</script><script type="math/tex; mode=display">x = -\frac{n*k(真)}{m(真)} \quad</script><p>布隆过滤器优缺点</p>
<p>优点：</p>
<ul>
<li>节省空间：不需要存储数据本身，只需要存储数据对应hash比特位</li>
<li>时间复杂度低：插入和查找的时间复杂度都为O(k)，k为哈希函数的个数</li>
</ul>
<p>缺点：</p>
<ul>
<li>存在假阳性：布隆过滤器判断存在，可能出现元素不在集合中；判断准确率取决于哈希函数的个数</li>
<li>不能删除元素：如果一个元素被删除，但是却不能从布隆过滤器中删除，这也是造成假阳性的原因了</li>
</ul>
<p>布隆过滤器适用场景</p>
<ul>
<li>爬虫系统url去重</li>
<li>垃圾邮件过滤</li>
<li>黑名单</li>
</ul>
<hr>
<h2 id="一致性哈希原理"><a href="#一致性哈希原理" class="headerlink" title="一致性哈希原理"></a><strong>一致性哈希原理</strong></h2><p>后端程序员基本必考</p>
<p>一种特殊的哈希算法，目的是解决分布式缓存的问题</p>
<p>在移除或者添加一个服务器时，能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表中存在的动态伸缩等问题</p>
<p>在分布式问题当中，数据服务器可能需要存大量数据，一台服务器可能承担不下来，所以需要多台服务器来完成数据的存储，这个时候就存在了一个问题：数据到底存到哪台服务器上。</p>
<p>经典分布式数据库的设计:</p>
<p>当逻辑端需要存数据时，将这个数据调用一个哈希函数，算出来一个值，再模上你服务器的数量</p>
<p>但这种设计方式存在一个问题，如果我需要删除或添加一台服务器，那么之前我用模服务器数量的方式就不能用了，那么这些服务器上的数据都需要重新算一遍哈希值然后模一下服务器的数量。增加机器和删除机器，数据迁移是全量的。</p>
<p>解决这个问题，就是想办法怎样不用模的方式来分配数据，让迁移量不会达到全量。</p>
<h3 id="一致性哈希解决"><a href="#一致性哈希解决" class="headerlink" title="一致性哈希解决"></a><strong>一致性哈希解决</strong></h3><p>这里用MD5算法来举例，MD5的范围是0~2^64-1</p>
<ul>
<li><p>将这个范围想象成一个环。对服务器通过哈希函数，算出一个哈希值。</p>
</li>
<li><p>多个服务器可以算出多个哈希值，哈希值对应环中的某个点，就可以想象成将这些服务器插入到了环中</p>
</li>
<li><p>当逻辑服务器需要存储数据到数据服务器时，将数据通过哈希函数算出一个哈希值，这个哈希值一定会在环上的某个位置。</p>
</li>
<li><p>直到这个位置之后，按照位置将数据放到顺时针离我最近的那台机器上。</p>
</li>
</ul>
<p>通过一个request确定存到哪台服务器的实现机制是什么？</p>
<p>机制实现:在逻辑端，将数据端服务器的哈希值进行一个排序，存入到逻辑端服务器中的数组中。</p>
<p>当我要存一个数据，通过哈希函数算出来一个哈希值。然后在逻辑服务器里面的存服务器哈希值的数组中做二分查找，就可以找到大于等于这个哈希值最左边的那个数。就可以知道这个数据要存入哪个数据服务器了。如果找不到大于等于这个哈希值的数，那么就将这个数存入到哈希值最小的那台服务器上(因为是环状)</p>
<p><strong>与经典分布式数据库相比的好处:</strong></p>
<p>数据服务器的增加、删除时，数据迁移量很低，因为每个服务器都在环上，当添加一台服务器或者删除一台服务器时，并不需要取模(避免了全量迁移),而是只需要迁移一部分。</p>
<p><strong>存在的问题</strong></p>
<ol>
<li><p>数据服务器数量很少的时候，可能一上来不一定做到环的均分(因为要考虑负载均衡)。</p>
</li>
<li><p>即便我服务器数量很少，一上来就能对环做到均分，但是当我增加或减少一台服务器时，就不能对环做到均分了。</p>
</li>
</ol>
<h3 id="解决一致性哈希存在的两个问题"><a href="#解决一致性哈希存在的两个问题" class="headerlink" title="解决一致性哈希存在的两个问题"></a><strong>解决一致性哈希存在的两个问题</strong></h3><p><strong>虚拟节点技术</strong></p>
<p>对每台数据服务器，都给他分配1000字符串(不一定是1000，举例)。可以看作每一台服务器都有1000个虚拟点，都是1000个代表字符串。</p>
<p>对每一个字符串都算出一个哈希值，当作环中的一个点。</p>
<p>这个技术很好的解决了服务器数量少和增删服务器时对环做不到均分的问题了。</p>
<p>虚拟节点之间数据的迁移也是很好实现的。因为每个服务器都有实际的路由表，查找到需要迁移数据的虚拟节点和接收数据迁移的虚拟节点，然后将数据传递过去就可以了。</p>
<p><strong>一致性哈希还可以管理负载</strong></p>
<p>如果一台服务器的性能很强，那么在分配字符串时可以多给它分配一些字符串，如果一台服务器的性能很弱，那么在分配字符串时就可以少给他分配一些字符串。</p>
<p>这样就可以通过这种方式实现负载的管理。</p>
<p><strong>现在各大公司底层分布式数据库都用到了这个原理</strong>，这篇论文被誉为谷歌改变世界三驾马车之一。</p>
<p><strong>一致性哈希算法的简单概述</strong></p>
<p>一致性哈希算法将整个哈希值空间映射成一个虚拟的圆环，整个哈希空间的取值范围为0~232-1。</p>
<p>整个空间按顺时针方向组织。0~232-1在零点中方向重合。接下来使用如下算法对服务请求进行映射，将服务请求使用哈希算法算出对应的hash值，然后根据hash值的位置沿圆环顺时针查找，第一台遇到的服务器就是所对应的处理请求服务器。当增加一台新的服务器，受影响的数据仅仅是新添加的服务器到其环空间中前一台的服务器（也就是顺着逆时针方向遇到的第一台服务器）之间的数据，其他都不会受到影响。综上所述，一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据，具有较好的容错性和可扩展性。</p>
<hr>
<h2 id="并查集"><a href="#并查集" class="headerlink" title="并查集"></a><strong>并查集</strong></h2><p>题目：一个矩阵只有0和1两种值，每个位置都可以和自己的上、下、左、右四个位置相连，如果有一片1连在一起，这个部分叫做一个岛，求一个矩阵中有多少个岛</p>
<hr>
<p>并查集结构:</p>
<p>{a},{b},{c},{d},{e}</p>
<p>提供两个操作，查询两个样本是否属于一个集合、合并两个集合</p>
<p>经典结构都不太合适，所以提供了一个并查集结构。</p>
<p>把每一个样本当作一个图，上述集合中因为都是一个样本是一个集合，所以将一个样本看作一个单独的图，图的节点指向自己。</p>
<p><strong>查询两个样本是否属于一个集合</strong></p>
<p>{a},{b}</p>
<p>通过找两个集合中往上指的指针，找到最后一个元素(代表元素)，看两个集合的代表元素是否相同，相同则是同一个集合，不相同则不是同一个集合。</p>
<p><strong>优化查询</strong></p>
<p>在合并集合的过程中，可能往上指的链存在过长的情况，使得查询速度降低。这时候可以在查询两个样本是否属于一个集合的过程后，将这条路径上的所有节点都指向顶部元素，这样下次再查找的时候就能一步到位。</p>
<p><strong>合并两个集合成为一个集合</strong><br>通过找两个集合中往上指的指针，看最顶节点哪个被指向的多，数量较少的集合的顶端，要挂在数量较多的顶端的底下。</p>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">public static <span class="keyword">class</span> Element&lt;V&gt;&#123;</span><br><span class="line">    public V value;</span><br><span class="line">    public <span class="constructor">Element(V <span class="params">value</span>)</span>&#123;</span><br><span class="line">        this.value = value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">public static <span class="keyword">class</span> UnionFindSet&lt;V&gt;&#123;</span><br><span class="line">    public HashMap&lt;V,Element&lt;V&gt;&gt; elementMap;</span><br><span class="line">    <span class="comment">// key 某个元素，value 该元素的父</span></span><br><span class="line">    public HashMap&lt;Element&lt;V&gt;,Element&lt;V&gt;&gt; fatherMap;</span><br><span class="line">    <span class="comment">//key 表示代表节点,value表示代表节点代表的有几个元素</span></span><br><span class="line">    public HashMap&lt;Element&lt;V&gt;,Integer&gt; sizeMap;</span><br><span class="line"></span><br><span class="line">    public <span class="constructor">UnionFindSet(List&lt;V&gt; <span class="params">list</span>)</span>&#123;</span><br><span class="line">        elementMap = <span class="keyword">new</span> HashMap&lt;&gt;<span class="literal">()</span>;</span><br><span class="line">        fatherMap = <span class="keyword">new</span> HashMap&lt;&gt;<span class="literal">()</span>;</span><br><span class="line">        sizeMap = <span class="keyword">new</span> HashMap&lt;&gt;<span class="literal">()</span>;</span><br><span class="line">        <span class="comment">//初始化，都将每个元素设置为一个集合</span></span><br><span class="line">        <span class="keyword">for</span>(V value : <span class="built_in">list</span>)&#123;</span><br><span class="line">            Element&lt;V&gt; element = <span class="keyword">new</span> Element&lt;V&gt;(value);</span><br><span class="line">            elementMap.put(value,element);</span><br><span class="line">            father.put(element,element);</span><br><span class="line">            sizeMap.put(element,<span class="number">1</span>);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line">public boolean is<span class="constructor">SameSet(V <span class="params">a</span>,V <span class="params">b</span>)</span>&#123;</span><br><span class="line">    <span class="comment">//并查集的前提是有初始化，如果用户给的样本没有被初始化过，就没办法告诉用户该元素是否在集合中。</span></span><br><span class="line">    <span class="keyword">if</span>(elementMap.contains<span class="constructor">Key(<span class="params">a</span>)</span><span class="operator"> &amp;&amp; </span>elementMap.contains<span class="constructor">Key(<span class="params">b</span>)</span>)&#123;</span><br><span class="line">        return find<span class="constructor">Head(<span class="params">elementMap</span>.<span class="params">get</span>(<span class="params">a</span>)</span>)<span class="operator"> == </span>find<span class="constructor">Head(<span class="params">elementMap</span>.<span class="params">get</span>(<span class="params">b</span>)</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    return <span class="literal">false</span>;</span><br><span class="line">&#125;</span><br><span class="line">public void union(V a,V b)&#123;</span><br><span class="line">    <span class="keyword">if</span>(elementMap.contains<span class="constructor">Key(<span class="params">a</span>)</span><span class="operator"> &amp;&amp; </span>elementMap.contains<span class="constructor">Key(<span class="params">b</span>)</span>)&#123;</span><br><span class="line">        Element&lt;V&gt; aF = find<span class="constructor">Head(<span class="params">elementMap</span>.<span class="params">get</span>(<span class="params">a</span>)</span>);</span><br><span class="line">        Element&lt;V&gt; bF = find<span class="constructor">Head(<span class="params">elementMap</span>.<span class="params">get</span>(<span class="params">b</span>)</span>);</span><br><span class="line">        <span class="keyword">if</span>(aF != bF)&#123;</span><br><span class="line">            Element&lt;V&gt; big = sizeMap.get(aF) &gt;= sizeMap.get(bF) ? aF : bF;</span><br><span class="line">            Element&lt;V&gt; small = big<span class="operator"> == </span>aF ? bF : aF;</span><br><span class="line">            fatherMap.put(small,big);</span><br><span class="line">            sizeMap.put(big,sizeMap.get(aF) + sizeMap.get(bF));</span><br><span class="line">            <span class="comment">//这个时候这个节点已经不是代表节点了，所以要把它从代表节点的集合中删掉。</span></span><br><span class="line">            sizeMap.remove(small);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">public Element&lt;V&gt; find<span class="constructor">Head(Element&lt;V&gt; <span class="params">element</span>)</span>&#123;</span><br><span class="line">    Stack&lt;Element&lt;V&gt;&gt; path = <span class="keyword">new</span> Stack&lt;&gt;<span class="literal">()</span>;</span><br><span class="line">    <span class="keyword">while</span>(element != fatherMap.get(element))&#123;</span><br><span class="line">        path.push(element);</span><br><span class="line">        element = fatherMap.get(element);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//将路径中所有节点的父设置成对顶部元素的。</span></span><br><span class="line">    <span class="keyword">while</span>(!path.is<span class="constructor">Empty()</span>)&#123;</span><br><span class="line">        fatherMap.put(path.pop<span class="literal">()</span>,element);</span><br><span class="line">    &#125;</span><br><span class="line">    return element;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如何设计一个并行算法解决上述那个问题：</p>
<p>这样去思考，先将矩阵切成两半，然后用两个CPU去统计各自的那一半</p>
<p>然后收集被感染点感染的边界的点。</p>
<p>找到所有的被感染点感染的边界的点，让他们各自成为一个集合。</p>
<p>如果发现有两个集合是因为被切成两半才被分开的，那么就将这两个集合合并成一个集合。最后看有几个集合就有几个岛。</p>
<hr>
<h2 id="KMP算法解决的问题"><a href="#KMP算法解决的问题" class="headerlink" title="KMP算法解决的问题"></a><strong>KMP算法解决的问题</strong></h2><p>KMP用来求子串问题</p>
<p>字符串str1和str2，str1是否包含str2，如果包含返回str2在str1中开始的位置。如何做到时间复杂度O(N)完成？</p>
<p>阐述概念:</p>
<p>最长的前缀和后缀的匹配长度</p>
<p>举例:abbabbk</p>
<p>前缀长度为1时，a。此时后缀为b</p>
<p>前缀长度为2时，ab，此时后缀bb</p>
<p>前缀长度为3时，abb，此时后缀abb  此时两者相等。</p>
<p>前缀长度为4时，abba，此时后缀babb</p>
<p>前缀长度为5时，abbab，此时后缀bbabb</p>
<p>前缀长度为6时，不讨论</p>
<p>则k的前缀和后缀相等的最大长度为3。</p>
<p><a target="_blank" rel="noopener" href="https://www.bilibili.com/video/BV1kQ4y1h7ok?p=12&amp;share_source=copy_web">https://www.bilibili.com/video/BV1kQ4y1h7ok?p=12&amp;share_source=copy_web</a><br><figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">int</span> getIndexOf(String s,String m)&#123;</span><br><span class="line">    <span class="keyword">if</span>(s == <span class="literal">null</span> || m == <span class="literal">null</span> || m.length() &lt; <span class="number">1</span> || s.length() &lt; m.length())&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">-1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">char</span>[] str1 = s.toCharArray();</span><br><span class="line">    <span class="built_in">char</span>[] str2 = m.toCharArray();</span><br><span class="line">    <span class="built_in">int</span> i1 = <span class="number">0</span>;<span class="comment">//str1来到的位置</span></span><br><span class="line">    <span class="built_in">int</span> i2 = <span class="number">0</span>;<span class="comment">//str2来到的位置</span></span><br><span class="line">    <span class="built_in">int</span>[] <span class="keyword">next</span> = getNextArray(str2);</span><br><span class="line">    <span class="comment">//如果i1越界，代表匹配失败，如果i2越界，代表匹配成功</span></span><br><span class="line">    <span class="keyword">while</span>(i1 &lt; str1.length &amp;&amp; i2 &lt; str2.length)&#123;</span><br><span class="line">        <span class="keyword">if</span>(str1[i1] == str2[i2])&#123;</span><br><span class="line">            <span class="comment">//两者相同时，同时往前跳</span></span><br><span class="line">            i1++;</span><br><span class="line">            i2++;</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(<span class="keyword">next</span>[i2] == <span class="number">-1</span>)&#123;<span class="comment">//next[i2] == -1代表i2是出于0位置的</span></span><br><span class="line">            <span class="comment">//也就是说我i2已经到0位置的时候还与i1位置上的数配不出来，那么i1就加1再去检查</span></span><br><span class="line">            i1++;</span><br><span class="line">        &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">//i2还能继续往右推，所以就继续右推</span></span><br><span class="line">            i2 = <span class="keyword">next</span>[i2];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//i2越界了，i1-i2就是相匹配的开头</span></span><br><span class="line">    <span class="comment">//i2越界了，返回-1</span></span><br><span class="line">    <span class="keyword">return</span> i2 == str2.length ? i1 - i2 : <span class="number">-1</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">int</span>[] getNextArray(<span class="built_in">char</span>[] ms)&#123;</span><br><span class="line">    <span class="keyword">if</span>(ms.length == <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">int</span>[]&#123;<span class="number">-1</span>&#125;;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="built_in">int</span>[] <span class="keyword">next</span>= <span class="keyword">new</span> <span class="built_in">int</span>[ms.length];</span><br><span class="line">    <span class="keyword">next</span>[<span class="number">0</span>] = <span class="number">-1</span>;</span><br><span class="line">    <span class="keyword">next</span>[<span class="number">1</span>] = <span class="number">0</span>;<span class="comment">//因为前缀不能取到整体，所以为0</span></span><br><span class="line">    <span class="built_in">int</span> i = <span class="number">2</span>;</span><br><span class="line">    <span class="built_in">int</span> cn = <span class="number">0</span>;<span class="comment">//cn是你要拿哪个位置的字符和i-1位置的字符比对</span></span><br><span class="line">    <span class="keyword">while</span>(i &lt; <span class="keyword">next</span>.length)&#123;</span><br><span class="line">        <span class="keyword">if</span>(ms[i<span class="number">-1</span>] == ms[cn])&#123;</span><br><span class="line">            <span class="keyword">next</span>[i++] = ++cn;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">else</span> <span class="keyword">if</span>(cn &gt; <span class="number">0</span>)&#123;</span><br><span class="line">            cn = <span class="keyword">next</span>[cn];</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">next</span>[i++] = <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">next</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="Manacher算法"><a href="#Manacher算法" class="headerlink" title="Manacher算法"></a><strong>Manacher算法</strong></h2><p>Manacher算法的核心是它的回文数组，这个回文数组不仅能帮助解决字符串回文问题，很多回文问题都可以用Manacher算法求</p>
<p>对于一个字符串 a b a b a b a a b a</p>
<p>给字符串中的每个字符加额外的符号，使得不管这个字符串的长度是奇数还是偶数，都让它变成偶数，使得需要考虑的情况只有一种(偶数情况)</p>
<pre><code>#a#b#a#b#a#b#a#a#b#a#
</code></pre><p>对字符串中每个字符的半径记录下来组成一个数组</p>
<p>记录下在字符串中对其取得的最远边界时的中心点C和所能扩大的最右侧的点R</p>
<p><strong>求回文子串的方式</strong></p>
<p><strong>讨论</strong></p>
<ol>
<li><p>在遍历的过程中，如果某个点i，它没有在最右回文右边界里，只能暴力扩(R变大)</p>
</li>
<li><p>来到一个点i，在最右回文右边界内部。取得最右回文右边界的中心点C和与R关于C的对称点L。那么i的对称点i’也一定在(L,R)范围内。</p>
<ol>
<li><p>如果i点的对称点i’的半径也在(L,R)范围内，则可以得出i的回文半径 = i’的回文半径</p>
</li>
<li><p>i’的回文区域，有一部分在(L,R)范围外，则i的回文半径就是(i,R)</p>
</li>
<li><p>如果i’的回文左区域正好与L重合，则i的回文半径至少为(i,R)，但不知道能不能到达更远，需要从R之外的字符开始再往外扩，然后确定答案(R可能变大)</p>
</li>
</ol>
</li>
</ol>
<figure class="highlight processing"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">char</span>[] <span class="title function_">manacherString</span>(<span class="built_in">String</span> <span class="built_in">str</span>)&#123;</span><br><span class="line">    <span class="type">char</span>[] charArr = <span class="built_in">str</span>.<span class="property">toCharArray</span>();</span><br><span class="line">    <span class="type">char</span>[] res = <span class="keyword">new </span><span class="class title_">char</span>[<span class="built_in">str</span>.<span class="property">length</span>() * <span class="number">2</span> + <span class="number">1</span>];</span><br><span class="line">    <span class="type">int</span> index = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i != res.<span class="property">length</span>; i++)&#123;</span><br><span class="line">        res[i] = (i &amp; <span class="number">1</span>) == <span class="number">0</span> ? <span class="string">&#x27;#&#x27;</span> : charArr[index++];</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">maxLcpsLength</span>(<span class="built_in">String</span> s)&#123;</span><br><span class="line">    <span class="keyword">if</span>(s == <span class="literal">null</span> || s.<span class="property">length</span>() == <span class="number">0</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">char</span>[] <span class="built_in">str</span> = <span class="title function_">manacherString</span>(s);<span class="comment">//加特殊字符的方法 1221 --&gt; #1#2#2#1#</span></span><br><span class="line">    <span class="type">int</span>[] pArr = <span class="keyword">new </span><span class="class title_">int</span>[<span class="built_in">str</span>.<span class="property">length</span>];<span class="comment">//回文半径数组</span></span><br><span class="line">    <span class="type">int</span> C = <span class="number">-1</span>;<span class="comment">//中心</span></span><br><span class="line">    <span class="type">int</span> R = <span class="number">-1</span>;<span class="comment">//回文右边界的再往右一个位置 最右的有效区是R-1位置</span></span><br><span class="line">    <span class="type">int</span> <span class="built_in">max</span> = Integer.<span class="property">MIN_VALUE</span>；<span class="comment">//扩出来的最大值</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i != <span class="built_in">str</span>.<span class="property">length</span>; i++)&#123;<span class="comment">//每一个位置都求回文半径</span></span><br><span class="line">        <span class="comment">//i至少的回文区域，先给pArr[i]</span></span><br><span class="line">        <span class="comment">//R &gt; i 证明i在R内,否则至少不用验证的区域是1(自己和自己构成回文串)</span></span><br><span class="line">        pArr[i] = R &gt; i ? Math.<span class="property">min</span>(pArr[<span class="number">2</span>*C - i],R - i) : <span class="number">1</span>;</span><br><span class="line">        <span class="comment">//暴力循环</span></span><br><span class="line">        <span class="keyword">while</span>(i + pArr[i] &lt; <span class="built_in">str</span>.<span class="property">length</span> &amp;&amp; i - pArr[i] &gt; <span class="number">-1</span>)&#123;</span><br><span class="line">            <span class="keyword">if</span>(<span class="built_in">str</span>[i + pArr[i]] == <span class="built_in">str</span>[i - pArr[i]])</span><br><span class="line">                pArr[i]++;</span><br><span class="line">            <span class="keyword">else</span> &#123;</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(i + pArr[i] &gt; R)&#123;</span><br><span class="line">            R = i + pArr[i];</span><br><span class="line">            C = i;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">max</span> = Math.<span class="property">max</span>(<span class="built_in">max</span>,pArr[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">max</span> - <span class="number">1</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="滑动窗口"><a href="#滑动窗口" class="headerlink" title="滑动窗口"></a><strong>滑动窗口</strong></h2><ol>
<li><p>窗口的左边界为L，右边界为R。左边界和右边界可以在一系列数之间滑动，而且左边界一定不能超过右边界。</p>
</li>
<li><p>设置一个双端队列，双端队列的头部和尾部都可以弹出和进入。双端队列严格遵照单调性，头部高、尾部低。</p>
</li>
<li><p>如果窗口滑动，进入双端队列的数破坏了双端队列的单调性了，就从尾部弹出比我要放进去的数小的数，直到不破坏单调性为止。</p>
</li>
<li><p>头部一直维持滑动窗口的最大数</p>
</li>
<li><p>双端队列只存储数组中数的下标，不存放具体的值</p>
</li>
<li><p>双端队列中存储的是可能成为最大值的值</p>
</li>
</ol>
<figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">int</span>[] getMaxWindow(<span class="built_in">int</span>[] arr, <span class="built_in">int</span> w) &#123;</span><br><span class="line">    <span class="keyword">if</span> (arr == <span class="literal">null</span> || w &lt; <span class="number">1</span> || arr.length &lt; w) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// qmax 窗口最大值的更新结构</span></span><br><span class="line">    <span class="comment">// 放下标</span></span><br><span class="line">    LinkedList&lt;Integer&gt; qmax = <span class="keyword">new</span> LinkedList&lt;Integer&gt;();</span><br><span class="line">    <span class="built_in">int</span>[] res = <span class="keyword">new</span> <span class="built_in">int</span>[arr.length - w + <span class="number">1</span>];</span><br><span class="line">    <span class="built_in">int</span> <span class="keyword">index</span> = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span> (<span class="built_in">int</span> R = <span class="number">0</span>; R &lt; arr.length; R++) &#123;</span><br><span class="line">        <span class="keyword">while</span> (!qmax.isEmpty() &amp;&amp; arr[qmax.peekLast()] &lt;= arr[R]) &#123;</span><br><span class="line">            qmax.pollLast();</span><br><span class="line">        &#125;</span><br><span class="line">        qmax.addLast(R);</span><br><span class="line">        <span class="keyword">if</span> (qmax.peekFirst() == R - w) &#123;</span><br><span class="line">            qmax.pollFirst();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span> (R &gt;= w - <span class="number">1</span>) &#123;</span><br><span class="line">            res[<span class="keyword">index</span>++] = arr[qmax.peekFirst()];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="单调栈"><a href="#单调栈" class="headerlink" title="单调栈"></a><strong>单调栈</strong></h2><p><strong>窗口内最大值与最小值更新结构的原理与实现——单调栈</strong></p>
<p>如果有一堆数，我想知道任意一个数，左边离他最近比它大的和右边离他最近比它大的。</p>
<p>可以用单调栈来实现这个问题。单调栈可以从栈顶到栈底单调递减，也可以单调递增，具体看业务需求。</p>
<p>无重复值情况下：</p>
<p>想要求一个数左边离他最近的比它大的数和右边理他最近的比它大的数，就从数组的0坐标依次将元素放入数组，当放入你要求的那个数的时候，在这个数下面的就是左边比你大的数，再继续放入，如果有一个数放入的时候需要这个元素弹出，那么这个数就是右边离你最近比你大的数。</p>
<p>可以通过数组依次遍历整个数组，然后记录下每个数左边离他最近比它大、右边离他最近比它大的数</p>
<p>有重复值情况下：</p>
<p>当遇到重复值进栈的时候，一定会与另一个相同值相遇，这时候两个的坐标合并，例如1下标为止的数为4，3下标为止下的数也是4，所以合并后为{1,4}，他们左边位置的最大值为1坐标下面的数，右边离他们最近的最大值为让他们弹出去的那个数。</p>
<h3 id="数组中累积和与最小值的乘积，假设叫做指标A。给定一个正数数组，且指标A最大的值"><a href="#数组中累积和与最小值的乘积，假设叫做指标A。给定一个正数数组，且指标A最大的值" class="headerlink" title="数组中累积和与最小值的乘积，假设叫做指标A。给定一个正数数组，且指标A最大的值"></a><strong>数组中累积和与最小值的乘积，假设叫做指标A。给定一个正数数组，且指标A最大的值</strong></h3><p>流程:假设子数组必须包含一个元素i，而且这个i一定要是这个子数组的最小值，那在候选选组中，哪一个指标是最大的。将每一个元素都当作子数组中的最小值，利用单调栈求出所以后比这个元素大的数的子数组，那么指标A的最大值一定在这些子数组中。</p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/04/02/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%B8%89/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/04/02/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%B8%89/" class="post-title-link" itemprop="url">算法笔记(三)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-04-02 10:01:00" itemprop="dateCreated datePublished" datetime="2022-04-02T10:01:00+08:00">2022-04-02</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-03 10:47:12" itemprop="dateModified" datetime="2022-04-03T10:47:12+08:00">2022-04-03</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="贪心算法"><a href="#贪心算法" class="headerlink" title="贪心算法"></a><strong>贪心算法</strong></h1><p>在某一个标准下，优先考虑最满足标准的样本，最后考虑最不满足标准的样本，最终得到一个答案的算法，叫做贪心算法。</p>
<p>也就是说，不从整体最优上加以考虑，所做出的是在某种意义上的局部最优解</p>
<hr>
<p>一些项目要占用一个会议室宣讲，会议室不能同时容纳两个项目的宣讲。给你每一个项目开始的时间和结束的时间(给你一个数组，里面是一个个具体的项目)，你来安排宣讲的日程，要求会议室进行的宣讲的场次最多。返回这个最多的宣讲场次。</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">static</span> <span class="keyword">class</span> <span class="title class_">Progarm</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> start;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> end;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Program</span><span class="params">(<span class="type">int</span> start,<span class="type">int</span> end)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.start = start;</span><br><span class="line">        <span class="keyword">this</span>.end = end;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="type">static</span> <span class="keyword">class</span> <span class="title class_">ProgramComparator</span> implements Comparator&lt;Progarm&gt;&#123;</span><br><span class="line">    @<span class="function">Override</span></span><br><span class="line"><span class="function">    <span class="keyword">public</span> <span class="type">int</span> <span class="title">compare</span><span class="params">(Program o1,Program o2)</span></span>&#123;</span><br><span class="line">        <span class="keyword">return</span> o1.end - o2.end;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//timePoint是会议室开始营业时间</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> <span class="type">int</span> <span class="title">bestArrange</span><span class="params">(Progarm[] progarms,<span class="type">int</span> timePoint)</span></span>&#123;</span><br><span class="line">    <span class="comment">//按照结束时间早的进行排序</span></span><br><span class="line">    Arrays.<span class="built_in">sort</span>(programs,<span class="keyword">new</span> <span class="built_in">ProgramComparator</span>());</span><br><span class="line">    <span class="type">int</span> result = <span class="number">0</span>;</span><br><span class="line">    <span class="comment">//从左往右依次遍历所有会议</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; program.length;i++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(timePoint &lt;= programs[i].start)&#123;</span><br><span class="line">            result++;</span><br><span class="line">            timePoint = programs[i].end;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="贪心算法在笔试的时候的解题思路"><a href="#贪心算法在笔试的时候的解题思路" class="headerlink" title="贪心算法在笔试的时候的解题思路"></a><strong>贪心算法在笔试的时候的解题思路</strong></h3><ol>
<li><p>实现一个不依靠贪心策略的解法X，可以用最暴力(写的多了会发现暴力解法是可以复用的)的尝试</p>
</li>
<li><p>脑补出贪心策略A、贪心策略B、贪心策略C…</p>
</li>
<li><p>用解法X和对数器，去验证每一个贪心策略，用实验的方式得知哪个贪心策略正确</p>
</li>
<li><p>不要纠结贪心策略的证明</p>
</li>
</ol>
<p>贪心算法不太好准备，因为业务不同，贪心思想也不同。需要自己去练习，累计经验。<strong>但也得要写模板，写对数器的模板。</strong></p>
<p>贪心算法一般出现在笔试题当中，出现的概率挺大，但篇幅不大，频率平均是5个算法题出现一个贪心算法类型。</p>
<p>但是贪心算法出现在面试中是比较少见的，因为一个是贪心算法的代码非常短，没有办法考coding。第二个是贪心算法的题目是0&#x2F;1的问题，要么找对贪心策略要么找错贪心策略，不存在什么优化技巧之类的，所以区分度不是很高。如果面试官想要淘汰掉一部分人可能出贪心算法，但为了区分度的话不会出这种题。</p>
<hr>
<h2 id="PriorityQueue的使用"><a href="#PriorityQueue的使用" class="headerlink" title="PriorityQueue的使用"></a><strong>PriorityQueue的使用</strong></h2><p>基于优先级堆的无限优先级queue 。 优先级队列的元素根据它们的有序natural ordering ，或由一个Comparator在队列构造的时候提供，这取决于所使用的构造方法。 优先队列不允许null元素。 依靠自然排序的优先级队列也不允许插入不可比较的对象（这样做可能导致ClassCastException ）。 </p>
<p>PriorityQueue():创建一个PriorityQueue ，具有默认的初始容量（11），根据它们的natural ordering对其元素进行排序。</p>
<p>PriorityQueue(Collection&lt;? extends E&gt; c):创建一个 PriorityQueue集合中的元素的PriorityQueue。</p>
<p>PriorityQueue(Comparator&lt;? super E&gt; comparator):创建具有默认初始容量的PriorityQueue，并根据指定的比较器对其元素进行排序。</p>
<p>方法摘要：</p>
<p>boolean add(E e)  将指定的元素插入到此优先级队列中。 </p>
<p>void clear()  从此优先级队列中删除所有元素。 </p>
<p>boolean contains(Object o)  如果此队列包含指定的元素，则返回 true 。</p>
<p>Iterator<E> iterator()  返回此队列中的元素的迭代器。 </E></p>
<p>boolean offer(E e)  将指定的元素插入到此优先级队列中。 </p>
<p>E peek()  检索但不删除此队列的头，如果此队列为空，则返回 null。</p>
<p>E poll()  检索并删除此队列的头，如果此队列为空，则返回 null 。 </p>
<p>int size()  返回此集合中的元素数。 </p>
<p>Object[] toArray()  返回一个包含此队列中所有元素的数组。</p>
<hr>
<p>输入：</p>
<p>正数数组costs、正数数组profits、正数K、正数m。</p>
<p>含义：</p>
<p>costs[i]表示i号项目的花费</p>
<p>profits[i]表示i号项目在扣除花费之后还能挣到的钱(利润)</p>
<p>K表示你只能串行的最多做K个项目</p>
<p>m表示你的初始资金</p>
<p>说明:你每做完一个项目，马上获得利润，可以支持你去做下一个项目。输出：你最后获得的最大钱数</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MinCostComparator</span> <span class="keyword">implements</span> <span class="title class_">Comparator</span>&lt;Node&gt;&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(Node o1,Node o2)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> o1.c - o2.c;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">MaxProfitComparator</span> <span class="keyword">implements</span> <span class="title class_">Comparator</span>&lt;Node&gt;&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">compare</span><span class="params">(Node o1,Node o2)</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> o2.p - o1.p;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="type">int</span> <span class="title function_">findMaximizedCapital</span><span class="params">(<span class="type">int</span> k,<span class="type">int</span> w,<span class="type">int</span>[] Profits,<span class="type">int</span>[] Capital)</span>&#123;</span><br><span class="line">    PriorityQueue&lt;Node&gt; minCostQ = <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>&lt;Node&gt;(<span class="keyword">new</span> <span class="title class_">MinCostComparator</span>);</span><br><span class="line">    PriorityQueue&lt;Node&gt; maxProfitQ = <span class="keyword">new</span> <span class="title class_">PriorityQueue</span>&lt;&gt;(<span class="keyword">new</span> <span class="title class_">MaxProfitComparator</span>);</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>; i &lt; Profits.length;i++)&#123;</span><br><span class="line">        minCostQ.add(<span class="keyword">new</span> <span class="title class_">Node</span>(Profits[i],Capital[i]));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> <span class="variable">i</span> <span class="operator">=</span> <span class="number">0</span>;i &lt; K;i++)&#123;</span><br><span class="line">        <span class="keyword">while</span>(!minCostQ.isEmpty() &amp;&amp; minCostQ.peek().c &lt;= w)&#123;</span><br><span class="line">            maxProfitQ.add(minCostQ.poll());</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(maxProfitQ.isEmpty())&#123;</span><br><span class="line">            <span class="keyword">return</span> w;</span><br><span class="line">        &#125;</span><br><span class="line">        w += maxProfitQ.poll().p;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> w;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>


<p>额外插入一个堆的题目：</p>
<p>一个数据流中，随时可以取得中位数</p>
<p>准备一个大根堆和小根堆</p>
<ol>
<li><p>给的第一个数字直接入大根堆</p>
</li>
<li><p>再获得一个数，判断当前获得的数是否小于大根堆的堆顶元素</p>
</li>
<li><p>如果是，当前元素入大根堆，如果不是，当前元素入小根堆</p>
</li>
<li><p>每次循环都判断两个堆的大小，如果两者大小相差2，那么较大的那个堆的堆顶弹出进较小的那个堆的堆顶</p>
</li>
</ol>
<h2 id="N皇后问题"><a href="#N皇后问题" class="headerlink" title="N皇后问题"></a><strong>N皇后问题</strong></h2><p>N皇后问题是指在N*N的棋盘上要摆N个皇后，要求任何两个皇后不同行、不同列，也不在同一条斜线上</p>
<p>给定一个整数n，返回N皇后的摆法有多少种。</p>
<p>n&#x3D;1，返回1</p>
<p>n&#x3D;2或3，2皇后和3皇后问题无论怎么摆放都不行，返回0。</p>
<p>n&#x3D;8，返回92</p>
<figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">public</span> static <span class="type">int</span> num1(<span class="type">int</span> n)&#123;</span><br><span class="line">    <span class="keyword">if</span>(n &lt; <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span>[] <span class="type">record</span> = <span class="built_in">new</span> <span class="type">int</span>[n];//用一个单数组表示   <span class="type">record</span>[i] = j 表示i行j列处放皇后</span><br><span class="line">    <span class="keyword">return</span> process1(<span class="number">0</span>,<span class="type">record</span>,n);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">//i表示现在来到了第几行</span><br><span class="line">//n表示整体一共多少行</span><br><span class="line">//返回值是，摆完所有的皇后，合理的摆法有多少种</span><br><span class="line"><span class="built_in">public</span> static <span class="type">int</span> process1(<span class="type">int</span> i,<span class="type">int</span>[] <span class="type">record</span>,<span class="type">int</span> n)&#123;</span><br><span class="line">    <span class="keyword">if</span>(i == n)&#123;//i = n 是终止行，n是n行n列的下一行，不属于<span class="type">record</span>数组，如果能执行这条语句，就证明前面行摆的都符合了条件，那么也就代表着我找到了一种摆法。</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">int</span> res = <span class="number">0</span>;</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> j = <span class="number">0</span>;j &lt; n; j++)&#123;//当前行在i行，尝试i行所有的列 <span class="comment">--&gt; j</span></span><br><span class="line">        //当前i行的皇后，放在j列，会不会和之前(<span class="number">0.</span>..i<span class="number">-1</span>)的皇后，共行共列或者共斜线</span><br><span class="line">        //如果是，认为有效</span><br><span class="line">        //如果不是，认为无效</span><br><span class="line">        <span class="keyword">if</span>(isValid(<span class="type">record</span>,i,j))&#123;</span><br><span class="line">            <span class="type">record</span>[i] = j;</span><br><span class="line">            res += process1(i+<span class="number">1</span>,<span class="type">record</span>,n);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">public</span> static <span class="type">boolean</span> isValid(<span class="type">int</span>[] <span class="type">record</span>,<span class="type">int</span> i,<span class="type">int</span> j)&#123;</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> k = <span class="number">0</span>; k &lt; i; k++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(j == <span class="type">record</span>[k] || Math.abs(<span class="type">record</span>[k]-j) == Math.abs(i-k))&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="keyword">false</span>;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">true</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>N皇后问题的时间复杂度为O(N^N)，该指标已经没有办法优化，已经是最优解。<strong>但常数部分还可以优化，而且优化的方式有多种</strong></p>
<p>这里演示的这种优化方式，就是利用位运算的特性，代替record的检查</p>
<figure class="highlight hsp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line">public static <span class="keyword">int</span> num2(<span class="keyword">int</span> n)&#123;</span><br><span class="line">    <span class="keyword">if</span>(n &lt;<span class="number">1</span> || n&gt; <span class="number">32</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span><span class="comment">;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//该行表示将一个32位的数，n皇后问题，后面n个1，前面全部为0。这个数不代表任何信息，只使用这个数的位信息</span></span><br><span class="line">    <span class="comment">//例如n为8，00000000000000000000000011111111</span></span><br><span class="line">    <span class="keyword">int</span> <span class="keyword">limit</span> = n == <span class="number">32</span> ? <span class="number">-1</span> : (<span class="number">1</span> &lt;&lt; n) <span class="number">-1</span><span class="comment">;</span></span><br><span class="line">    <span class="comment">//在limit限制的范围内，一开始我行、斜线都没限制的情况下，有多少种</span></span><br><span class="line">    <span class="keyword">return</span> process2(<span class="keyword">limit</span>,<span class="number">0</span>,<span class="number">0</span>,<span class="number">0</span>)<span class="comment">;</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//limit是做限制用的，通过前面的运算已经得出limit的后n位是1了，那么下面的函数就被限制在是1的范围内去尝试了</span></span><br><span class="line"><span class="comment">//leftDiaLim 左斜线的限制，1的位置不能放皇后，0的位置可以</span></span><br><span class="line"><span class="comment">//rightDiaLim 右斜线的限制，1的位置不能放皇后，0的位置可以</span></span><br><span class="line">public static <span class="keyword">int</span> process2(<span class="keyword">int</span> <span class="keyword">limit</span>,<span class="keyword">int</span> colLim,<span class="keyword">int</span> leftDiaLim, <span class="keyword">int</span> rightDiaLim)&#123;</span><br><span class="line">    <span class="keyword">if</span>(colLim == <span class="keyword">limit</span>)&#123; <span class="comment">//当列上的限制和limit一样了，代表所有位置都被限制了，这时候代表找到了一种放置</span></span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span><span class="comment">;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">int</span> <span class="keyword">pos</span> = <span class="number">0</span><span class="comment">;</span></span><br><span class="line">    <span class="keyword">int</span> mostRightOne = <span class="number">0</span><span class="comment">;</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">//列的限制 | 左对角线的限制 | 右对角线的限制 = 总限制 (1代表能放皇后，0代表不可以放皇后)</span></span><br><span class="line">    <span class="comment">// 与limit进行与操作后，会将pos 的前32-n位数全部置为0，这样这些0就是不可以选皇后的位置，也就限制了选皇后的范围</span></span><br><span class="line">    <span class="keyword">pos</span> = <span class="keyword">limit</span> &amp; (~(colLim | leftDiaLim | rightDiaLim))<span class="comment">;</span></span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">    <span class="keyword">int</span> res = <span class="number">0</span><span class="comment">;</span></span><br><span class="line">    <span class="keyword">while</span>(<span class="keyword">pos</span> != <span class="number">0</span>)&#123;</span><br><span class="line">        <span class="comment">//pos &amp; (~pos + 1)   把一个二进制的数，最右侧的1提取出来</span></span><br><span class="line">        <span class="comment">//提取出候选皇后位置状态中最右侧的依赖</span></span><br><span class="line">        <span class="comment">//因为只有为1的位置上才可以放皇后，所以这条语句是找出最右侧的1，然后提取出来。</span></span><br><span class="line">        mostRightOne = <span class="keyword">pos</span> &amp; (~<span class="keyword">pos</span> + <span class="number">1</span>)<span class="comment">;</span></span><br><span class="line">        <span class="comment">//这里将最右侧的1剪掉，也就是将这个1改为0</span></span><br><span class="line">        <span class="keyword">pos</span> = <span class="keyword">pos</span> - mostRightOne<span class="comment">;</span></span><br><span class="line">        <span class="comment">//limit不变</span></span><br><span class="line">        <span class="comment">//因为我在mostRightOne的位置放了皇后，所以接下来列的限制为colLim | mostRightOne的形式。</span></span><br><span class="line">        <span class="comment">//因为我在mostRightOne的位置放了皇后，所以接下来左斜线的限制为leftDiaLim | mostRightOne 完成后往左移一位</span></span><br><span class="line">        <span class="comment">//因为我在mostRightOne的位置放了皇后，所以接下来右斜线的限制为rightDiaLim | mostRightOne 完成后往右移一位</span></span><br><span class="line">        <span class="comment">//res 累加每种尝试，返回</span></span><br><span class="line">        res += process2(<span class="keyword">limit</span>,colLim | mostRightOne,(leftDiaLim | mostRightOne) &lt;&lt; <span class="number">1</span>,(rightDiaLim | mostRightOne) &gt;&gt;&gt; <span class="number">1</span>)<span class="comment">;</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> res<span class="comment">;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="暴力递归"><a href="#暴力递归" class="headerlink" title="暴力递归"></a><strong>暴力递归</strong></h2><ol>
<li><p>把问题转化为规模缩小了的同类问题的子问题</p>
</li>
<li><p>有明确的不需要继续进行递归的条件</p>
</li>
<li><p>有当得到了子问题的结果之后的决策过程</p>
</li>
<li><p>不记录每一个子问题的解</p>
</li>
</ol>
<h3 id="汉诺塔问题"><a href="#汉诺塔问题" class="headerlink" title="汉诺塔问题"></a><strong>汉诺塔问题</strong></h3><p>打印n层汉诺塔从最左边移动到最右边的全部过程</p>
<p>一般新手可能会弄不清楚怎么保证i-1在从start移动到other的过程中和从other移动到end的过程中，大圆盘一定在下面</p>
<p>其实这是从全局来考虑整个过程。其实递归算法并不需要全局考虑，只需要保证你拆分的每一步(整个过程可以被拆分成相类似的局部过程)都符合要求，那么整体也一定符合要求。</p>
<figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">public</span> static <span class="type">void</span> hanoi(<span class="type">int</span> n)&#123;</span><br><span class="line">    <span class="keyword">if</span>(n &gt; <span class="number">0</span>)&#123;</span><br><span class="line">        func(n,&quot;左&quot;,&quot;中&quot;,&quot;右&quot;);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> static <span class="type">void</span> func(<span class="type">int</span> i,String <span class="keyword">start</span>,String <span class="keyword">end</span>,String other)&#123;</span><br><span class="line">    <span class="keyword">if</span>(i == <span class="number">1</span>)&#123;</span><br><span class="line">        <span class="keyword">System</span>.<span class="keyword">out</span>.println(&quot;Move 1 from &quot; + <span class="keyword">start</span> + &quot;to&quot; + <span class="keyword">end</span>);</span><br><span class="line">    &#125;<span class="keyword">else</span> &#123;</span><br><span class="line">        func(i<span class="number">-1</span>,<span class="keyword">start</span>,other,<span class="keyword">end</span>);</span><br><span class="line">        <span class="keyword">System</span>.<span class="keyword">out</span>.println(&quot;Move &quot; +  i + &quot;from &quot; + <span class="keyword">start</span> + &quot;to&quot; + <span class="keyword">end</span>);</span><br><span class="line">        func(i<span class="number">-1</span>,other,<span class="keyword">end</span>,<span class="keyword">start</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="打印一个字串的全部子序列，包括空字符串"><a href="#打印一个字串的全部子序列，包括空字符串" class="headerlink" title="打印一个字串的全部子序列，包括空字符串"></a><strong>打印一个字串的全部子序列，包括空字符串</strong></h3><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//当前来到i位置，要和不要，走两条路</span></span><br><span class="line"><span class="comment">//res之前的选择，所形成的列表</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">process</span>(<span class="params"><span class="built_in">char</span>[] str,<span class="built_in">int</span> i,List&lt;Character&gt; res</span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(i == str.length)&#123;</span><br><span class="line">        <span class="comment">//打印列表</span></span><br><span class="line">        printList(res);</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    List&lt;Character&gt; resKeep = copyList(res);</span><br><span class="line">    resKeep.<span class="keyword">add</span>(str[i]);</span><br><span class="line">    process(str,i+<span class="number">1</span>,resKeep);<span class="comment">//要当前字符的路</span></span><br><span class="line">    List&lt;Character&gt; resNoInclude = copyList(res);</span><br><span class="line">    process(str,i+<span class="number">1</span>,resNoInclude);<span class="comment">//不要当前字符的路</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">printList</span>(<span class="params">List&lt;Character&gt; res</span>)</span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> List&lt;Character&gt; <span class="title">copyList</span>(<span class="params">List&lt;Character&gt; list</span>)</span>&#123;</span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">//省空间的做法，通过chs空间的复用实现</span></span><br><span class="line"><span class="comment">//当前来到i位置，要和不要，走两条路</span></span><br><span class="line"><span class="comment">//之前的选择，所形成的结果，是str</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">process</span>(<span class="params"><span class="built_in">char</span>[] chs,<span class="built_in">int</span> i</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(i == chs.length)&#123;</span><br><span class="line">        System.<span class="keyword">out</span>.println(String.valueOf(chs));</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    process(chs,i+<span class="number">1</span>);<span class="comment">//要当前字符的路</span></span><br><span class="line">    <span class="built_in">char</span> temp = chs[i];</span><br><span class="line">    chs[i] = <span class="number">0</span>;</span><br><span class="line">    process(chs,i+<span class="number">1</span>);<span class="comment">//不要当前字符的路</span></span><br><span class="line">    chs[i] = temp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="打印一个字符串的全部排列"><a href="#打印一个字符串的全部排列" class="headerlink" title="打印一个字符串的全部排列"></a><strong>打印一个字符串的全部排列</strong></h3><p>打印一个字符串的全部排列，要求不要出现重复的排列</p>
<figure class="highlight processing"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">ArrayList</span>&lt;<span class="built_in">String</span>&gt; <span class="title function_">Permutation</span>(<span class="built_in">String</span> <span class="built_in">str</span>)&#123;</span><br><span class="line">    <span class="built_in">ArrayList</span>&lt;<span class="built_in">String</span>&gt; res = <span class="keyword">new </span><span class="class title_">ArrayList</span>&lt;&gt;();</span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">str</span> == <span class="literal">null</span> || <span class="built_in">str</span>.<span class="property">length</span>() == <span class="number">0</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">char</span>[] chs = <span class="built_in">str</span>.<span class="property">toCharArray</span>();</span><br><span class="line">    <span class="title function_">process</span>(chs,<span class="number">0</span>,res);</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">process</span>(<span class="type">char</span>[] <span class="built_in">str</span>,<span class="type">int</span> i,<span class="built_in">ArrayList</span>&lt;<span class="built_in">String</span>&gt; res)&#123;</span><br><span class="line">    <span class="keyword">if</span>(i == <span class="built_in">str</span>.<span class="property">length</span>)&#123;</span><br><span class="line">        res.<span class="property">add</span>(<span class="built_in">String</span>.<span class="property">valueOf</span>(<span class="built_in">str</span>));</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="type">boolean</span>[] visit = <span class="keyword">new </span><span class="class title_">boolean</span>[<span class="number">26</span>];<span class="comment">//用于去重</span></span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> j = i; j&lt; <span class="built_in">str</span>; j++)&#123;</span><br><span class="line">        <span class="keyword">if</span>(!visit[<span class="built_in">str</span>[j] - <span class="string">&#x27;a&#x27;</span>])&#123;<span class="comment">//如果当前试过，那么就不再试了</span></span><br><span class="line">            <span class="title function_">swap</span>(<span class="built_in">str</span>,i,j);</span><br><span class="line">            <span class="title function_">process</span>(<span class="built_in">str</span>,i+<span class="number">1</span>,res);</span><br><span class="line">            <span class="title function_">swap</span>(<span class="built_in">str</span>,i,j);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">swap</span>(<span class="type">char</span>[] chs,<span class="type">int</span> i,<span class="type">int</span> j)&#123;</span><br><span class="line">    <span class="type">char</span> temp =chs[i];</span><br><span class="line">    chs[i] = chs[j];</span><br><span class="line">    chs[j] = temp;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="纸牌的先手后手拿问题"><a href="#纸牌的先手后手拿问题" class="headerlink" title="纸牌的先手后手拿问题"></a><strong>纸牌的先手后手拿问题</strong></h2><p>有一副纸牌 [10,20,5,9,100,70,46,35,24],两个人只能从最左边或者最右边拿纸牌，一个先手拿牌一个后手拿牌，最后谁手中的牌的总和大谁赢</p>
<figure class="highlight scss"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public static int <span class="built_in">win1</span>(int[] arr)&#123;</span><br><span class="line">    <span class="built_in">if</span>(arr == null || arr.length == <span class="number">0</span>)&#123;</span><br><span class="line">        return <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    return Math<span class="selector-class">.max</span>(f(arr,<span class="number">0</span>,arr.length-<span class="number">1</span>),<span class="built_in">s</span>(arr,<span class="number">0</span>,arr.length-<span class="number">1</span>));</span><br><span class="line">&#125;</span><br><span class="line">public static int <span class="built_in">f</span>(int[] arr,int i,int j)&#123;</span><br><span class="line">    <span class="built_in">if</span>(i == j)&#123;</span><br><span class="line">        return arr<span class="selector-attr">[i]</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    return Math<span class="selector-class">.max</span>(arr[i] + s(arr,i+<span class="number">1</span>,j),arr<span class="selector-attr">[j]</span> + <span class="built_in">s</span>(arr,i,j-<span class="number">1</span>));</span><br><span class="line">&#125;</span><br><span class="line">public static int <span class="built_in">s</span>(int[] arr,int i,int j)&#123;</span><br><span class="line">    <span class="built_in">if</span>(i == j)&#123;</span><br><span class="line">        return <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    return Math<span class="selector-class">.min</span>(f(arr,i+<span class="number">1</span>,j),<span class="built_in">f</span>(arr,i,j-<span class="number">1</span>));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="给你一个栈，请你逆序这个栈，不能申请额外的数据结构，只能使用递归函数。如何实现。"><a href="#给你一个栈，请你逆序这个栈，不能申请额外的数据结构，只能使用递归函数。如何实现。" class="headerlink" title="给你一个栈，请你逆序这个栈，不能申请额外的数据结构，只能使用递归函数。如何实现。"></a><strong>给你一个栈，请你逆序这个栈，不能申请额外的数据结构，只能使用递归函数。如何实现。</strong></h2><figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">int</span> process(<span class="built_in">char</span>[] <span class="built_in">str</span>,<span class="built_in">int</span> i)&#123;</span><br><span class="line">    <span class="keyword">if</span>(i == <span class="built_in">str</span>.length)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">1</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">str</span>[i] == <span class="string">&#x27;0&#x27;</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">str</span>[i] == <span class="string">&#x27;1&#x27;</span>)&#123;</span><br><span class="line">        <span class="built_in">int</span> res = process(<span class="built_in">str</span>,i + <span class="number">1</span>); <span class="comment">// i 自己作为单独的部分，后续有多少种方法</span></span><br><span class="line">        <span class="keyword">if</span>(i + <span class="number">1</span> &lt; <span class="built_in">str</span>.length)&#123;</span><br><span class="line">            res += process(<span class="built_in">str</span>,i+<span class="number">2</span>); <span class="comment">// (i和i+1)作为单独的部分，后续有多少种方法</span></span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(<span class="built_in">str</span>[i] == <span class="string">&#x27;2&#x27;</span>)&#123;</span><br><span class="line">        <span class="built_in">int</span> res = process(<span class="built_in">str</span>,i + <span class="number">1</span>); <span class="comment">//i自己作为单独的部分，后续有多少种方法</span></span><br><span class="line">        <span class="keyword">if</span>(i + <span class="number">1</span> &lt; <span class="built_in">str</span>.length &amp;&amp; (<span class="built_in">str</span>[i+<span class="number">1</span>] &gt;= <span class="string">&#x27;0&#x27;</span> &amp;&amp; <span class="built_in">str</span>[i + <span class="number">1</span>] &lt; = <span class="string">&#x27;6&#x27;</span>))&#123; </span><br><span class="line">            <span class="comment">//(i和i+1)作为单独的部分并且没有超过26，后续有多少种方法</span></span><br><span class="line">            res += process(<span class="built_in">str</span>,i + <span class="number">2</span>); </span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> res;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// str[i] == &#x27;3&#x27;~&#x27;9&#x27;</span></span><br><span class="line">    <span class="keyword">return</span> process(<span class="built_in">str</span>,i+<span class="number">1</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="01背包问题"><a href="#01背包问题" class="headerlink" title="01背包问题"></a><strong>01背包问题</strong></h2><p>给定两个长度都为N的数组weights和values，weights[i]和values[i]分别代表i号物品的重量和价值。给定一个正数bag，表示一个载重bag的袋子，你装的物品不能超过这个重量。返回你能装下最多的价值是多少。</p>
<figure class="highlight perl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">public static <span class="keyword">int</span> process1(<span class="keyword">int</span>[] weights,<span class="keyword">int</span>[] <span class="keyword">values</span>,<span class="keyword">int</span> i,<span class="keyword">int</span> alreadyweight,<span class="keyword">int</span> bag)&#123;</span><br><span class="line">    <span class="keyword">if</span>(alreadyweight &gt; bag)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>( i == weights.length)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> Math.max(</span><br><span class="line">        process1(weights,<span class="keyword">values</span>,i + <span class="number">1</span>,alreadyweight,bag),<span class="regexp">//</span>不要第i号货物</span><br><span class="line">        <span class="keyword">values</span>[i] + process1(weights,<span class="keyword">values</span>,i+<span class="number">1</span>,alreadyweight+ weights[i],bag)); <span class="regexp">//</span>要第i号货物</span><br><span class="line">    )</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>




































































      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/04/01/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%BA%8C/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/04/01/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%BA%8C/" class="post-title-link" itemprop="url">算法笔记(二)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-04-01 16:21:35" itemprop="dateCreated datePublished" datetime="2022-04-01T16:21:35+08:00">2022-04-01</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-02 21:18:22" itemprop="dateModified" datetime="2022-04-02T21:18:22+08:00">2022-04-02</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="算法基础"><a href="#算法基础" class="headerlink" title="算法基础"></a><strong>算法基础</strong></h1><h2 id="图的存储方式"><a href="#图的存储方式" class="headerlink" title="图的存储方式"></a><strong>图的存储方式</strong></h2><ol>
<li>邻接表</li>
</ol>
<p>只写直接邻居，间接邻居不管</p>
<ol start="2">
<li>邻接矩阵</li>
</ol>
<p>正方形的矩阵，适合于带有权值的图，有向图、无向图都能表示</p>
<p>对于两个边不相连的点，用无穷表示</p>
<p>对于两个边相连的点，用他们的权值表示</p>
<figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> Graph&#123;</span><br><span class="line">    <span class="built_in">public</span> HashMap&lt;<span class="type">Integer</span>,Node&gt; nodes;</span><br><span class="line">    <span class="built_in">public</span> HashSet&lt;Edge&gt; edges;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">public</span> Graph()&#123;</span><br><span class="line">        nodes = <span class="built_in">new</span> HashMap&lt;&gt;();</span><br><span class="line">        edges = <span class="built_in">new</span> HashSet&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> Node&#123;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> <span class="keyword">value</span>;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> <span class="keyword">in</span>;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> <span class="keyword">out</span>;</span><br><span class="line">    <span class="built_in">public</span> ArrayList&lt;Node&gt; nexts;</span><br><span class="line">    <span class="built_in">public</span> ArrayList&lt;Edge&gt; edges;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">public</span> Node(<span class="type">int</span> <span class="keyword">value</span>)&#123;</span><br><span class="line">        this.<span class="keyword">value</span> = <span class="keyword">value</span>;</span><br><span class="line">        <span class="keyword">in</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">out</span> = <span class="number">0</span>;</span><br><span class="line">        nexts=<span class="built_in">new</span> ArrayList&lt;&gt;();</span><br><span class="line">        edges = <span class="built_in">new</span> ArrayList&lt;&gt;();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> <span class="keyword">class</span> Edge&#123;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> weight;</span><br><span class="line">    <span class="built_in">public</span> Node <span class="keyword">from</span>;</span><br><span class="line">    <span class="built_in">public</span> Node <span class="keyword">to</span>;</span><br><span class="line"></span><br><span class="line">    <span class="built_in">public</span> Edge(<span class="type">int</span> weight,Node <span class="keyword">from</span>,Node <span class="keyword">to</span>)&#123;</span><br><span class="line">        this.weight = weight;</span><br><span class="line">        this.<span class="keyword">from</span> = <span class="keyword">from</span>;</span><br><span class="line">        this.<span class="keyword">to</span> <span class="keyword">to</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> calss GraphGenerator&#123;</span><br><span class="line">    <span class="built_in">public</span> static Graph createGraph(<span class="type">Integer</span>[][] matrix)&#123;</span><br><span class="line">        Graph graph = <span class="built_in">new</span> Graph();</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; matrix.length;i++)&#123;</span><br><span class="line">            <span class="type">Integer</span> <span class="keyword">from</span> = matrix[i][<span class="number">0</span>];</span><br><span class="line">            <span class="type">Integer</span> <span class="keyword">to</span> = matrix[i][<span class="number">1</span>];</span><br><span class="line">            <span class="type">Integer</span> weight = matrix[i][<span class="number">2</span>];</span><br><span class="line">            <span class="keyword">if</span>(!graph.nodes.containsKey(<span class="keyword">from</span>))&#123;</span><br><span class="line">                graph.nodes.put(<span class="keyword">from</span>,<span class="built_in">new</span> Node(<span class="keyword">from</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            <span class="keyword">if</span>(!graph.nodes.containsKey(<span class="keyword">to</span>))&#123;</span><br><span class="line">                graph.nodes.put(<span class="keyword">to</span>,<span class="built_in">new</span> Node(<span class="keyword">to</span>));</span><br><span class="line">            &#125;</span><br><span class="line">            Node fromNode = graph.nodes.<span class="keyword">get</span>(form);</span><br><span class="line">            Node toNode = graph.nodes.<span class="keyword">get</span>(<span class="keyword">to</span>);</span><br><span class="line">            Edge newEdge = <span class="built_in">new</span> Edge(weight,fromNode,toNode);</span><br><span class="line">            fromNode.nexts.<span class="keyword">add</span>(toNode);</span><br><span class="line">            fromNode.<span class="keyword">out</span>++;</span><br><span class="line">            toNode.<span class="keyword">in</span>++;</span><br><span class="line">            fromNode.edges.<span class="keyword">add</span>(newEdge);</span><br><span class="line">            graph.edges.<span class="keyword">add</span>(newEdge);</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> graph;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="图的宽度优先遍历"><a href="#图的宽度优先遍历" class="headerlink" title="图的宽度优先遍历"></a><strong>图的宽度优先遍历</strong></h2><ol>
<li><p>利用队列实现</p>
</li>
<li><p>从源节点开始依次按照宽度进队列，然后弹出</p>
</li>
<li><p>每弹出一个点，把该节点所有没有进过队列的邻接点放入队列</p>
</li>
<li><p>直到队列变空</p>
</li>
</ol>
<figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">dfs</span>(<span class="params">Node node</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(node == <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Queue&lt;Node&gt; queue = <span class="keyword">new</span> LinkedList&lt;&gt;();<span class="comment">//图中的点进队列</span></span><br><span class="line">    HashSet&lt;Node&gt; <span class="keyword">set</span> = <span class="keyword">new</span> HashSet&lt;&gt;();<span class="comment">//保证图中的点不要重复进队列</span></span><br><span class="line"></span><br><span class="line">    queue.<span class="keyword">add</span>(node);</span><br><span class="line">    <span class="keyword">set</span>.<span class="keyword">add</span>(node);</span><br><span class="line">    <span class="keyword">while</span>(!queue.isEmpty())&#123;</span><br><span class="line">        Node cur = queue.poll();</span><br><span class="line">        System.<span class="keyword">out</span>.println(cur.<span class="keyword">value</span>);</span><br><span class="line">        <span class="keyword">for</span>(Node next : cur.nexts)&#123;</span><br><span class="line">            <span class="keyword">if</span>(!<span class="keyword">set</span>.contains(next))&#123;</span><br><span class="line">                <span class="keyword">set</span>.<span class="keyword">add</span>(next);</span><br><span class="line">                queue.<span class="keyword">add</span>(next);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="图的广度优先遍历"><a href="#图的广度优先遍历" class="headerlink" title="图的广度优先遍历"></a><strong>图的广度优先遍历</strong></h2><ol>
<li><p>利用栈实现</p>
</li>
<li><p>从源节点开始把节点按照深度放入栈，然后弹出</p>
</li>
<li><p>每弹出一个点，把该节点下一个没有进过栈的邻接点放入栈</p>
</li>
<li><p>直到栈变空</p>
</li>
</ol>
<figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> <span class="type">void</span> <span class="title">dfs</span><span class="params">(Node node)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(node == null)&#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    Stack&lt;Node&gt; stack = <span class="keyword">new</span> Stack&lt;&gt;();</span><br><span class="line">    HashSet&lt;Node&gt; set = <span class="keyword">new</span> HashSet&lt;&gt;();</span><br><span class="line">    stack.<span class="built_in">add</span>(node);</span><br><span class="line">    set.<span class="built_in">add</span>(node);</span><br><span class="line">    System.out.<span class="built_in">println</span>(node.value);</span><br><span class="line">    <span class="keyword">while</span>(!stack.<span class="built_in">isEmpty</span>())&#123;</span><br><span class="line">        Node cur = stack.<span class="built_in">pop</span>();<span class="comment">//把当前点弹出</span></span><br><span class="line">        <span class="keyword">for</span>(Node node : cur.nexts)&#123;</span><br><span class="line">            <span class="keyword">if</span>(!set.<span class="built_in">contains</span>(next))&#123;</span><br><span class="line">                stack.<span class="built_in">push</span>(cur);<span class="comment">//当前点再放入栈</span></span><br><span class="line">                stack.<span class="built_in">push</span>(next);<span class="comment">//当前点的下一个点也放入栈</span></span><br><span class="line">                set.<span class="built_in">add</span>(next);</span><br><span class="line">                System.out.<span class="built_in">println</span>(next.value);</span><br><span class="line">                <span class="keyword">break</span>;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="拓扑排序算法"><a href="#拓扑排序算法" class="headerlink" title="拓扑排序算法"></a><strong>拓扑排序算法</strong></h2><p>适用范围：要求有向图，且有入度为0的节点，且没有环</p>
<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line">public static List<span class="tag">&lt;Node&gt;</span> sortedTopology(Graph graph)&#123;</span><br><span class="line">    //key  某一个<span class="keyword">node</span></span><br><span class="line">    <span class="title">//value</span>   剩余的入度</span><br><span class="line">    HashMap<span class="tag">&lt;Node,Integer&gt;</span> inMap = new HashMap<span class="tag">&lt;&gt;</span>();</span><br><span class="line">    //入度为<span class="number">0</span>的点，才能进这个队列</span><br><span class="line">    Queue<span class="tag">&lt;Node&gt;</span> zeroInQueue = new LinkedList<span class="tag">&lt;&gt;</span>();</span><br><span class="line">    for(<span class="keyword">Node</span> <span class="title">node</span> : garph.nodes.values())&#123;</span><br><span class="line">        inMap.put(<span class="keyword">node</span><span class="title">,node</span>.<span class="keyword">in</span>);</span><br><span class="line">        if(node.<span class="keyword">in</span> == <span class="number">0</span>)&#123;</span><br><span class="line">            zeroInQueue.add(<span class="keyword">node</span><span class="title">);</span></span><br><span class="line"><span class="title">        &#125;</span></span><br><span class="line"><span class="title">    &#125;</span></span><br><span class="line"><span class="title">    List</span><span class="tag">&lt;Node&gt;</span> result = new ArrayList<span class="tag">&lt;&gt;</span>();</span><br><span class="line">    while(!zeroInQueue.isEmpty())&#123;</span><br><span class="line">        <span class="keyword">Node</span> <span class="title">cur</span> = zeroInQueue.poll();</span><br><span class="line">        result.add(cur);</span><br><span class="line">        for(<span class="keyword">Node</span> <span class="title">next</span> : cur.nexts)&#123;</span><br><span class="line">            inMap.put(next,inMap.get(next) - <span class="number">1</span>);</span><br><span class="line">            if(inMap.get(next) == <span class="number">0</span>)&#123;</span><br><span class="line">                zeroInQueue.add(next);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    return result;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="Kruskal算法"><a href="#Kruskal算法" class="headerlink" title="Kruskal算法"></a><strong>Kruskal算法</strong></h2><p>适用范围：无向图</p>
<p>思想:</p>
<ol>
<li><p>从无向图中，找出最小权值的边，接下来再画出这个图的没有边的图，试着把这条边加上后，看会不会形成环，如果不会，则保留这个边</p>
</li>
<li><p>继续找最小权值的边，如果加上这个边后，会形成环，则将这条边忽略</p>
</li>
<li><p>继续进行上面两步操作</p>
</li>
</ol>
<h2 id="何为前缀树，如何生成前缀树"><a href="#何为前缀树，如何生成前缀树" class="headerlink" title="何为前缀树，如何生成前缀树"></a><strong>何为前缀树，如何生成前缀树</strong></h2><p>例如：一个字符串类型的数组arr1，另一个字符串类型的数组arr2。arr2中有哪些字符，是arr1中出现的？请打印。arr2中有哪些字符，是作为arr1中某个字符串前缀出现的，请打印。arr2中有哪些字符，是作为arr1中某个字符串前缀出现的？请打印arr2中出现次数最大的前缀。</p>
<figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">public</span> static <span class="keyword">class</span> TrieNode&#123;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> pass;</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> <span class="keyword">end</span>;</span><br><span class="line">    <span class="built_in">public</span> TrieNode[] nexts;</span><br><span class="line">    <span class="built_in">public</span> TrieNode()&#123;</span><br><span class="line">        pass = <span class="number">0</span>;</span><br><span class="line">        end = <span class="number">0</span>;</span><br><span class="line">        nexts = <span class="built_in">new</span> TrieNode[<span class="number">26</span>];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> static <span class="keyword">class</span> Trie&#123;</span><br><span class="line">    private TrieNode root;</span><br><span class="line">    <span class="built_in">public</span> Trie()&#123;</span><br><span class="line">        root = <span class="built_in">new</span> TrieNode();</span><br><span class="line">    &#125;</span><br><span class="line">    //加入字符串</span><br><span class="line">    <span class="built_in">public</span> <span class="type">void</span> <span class="keyword">insert</span>(String word)&#123;</span><br><span class="line">        <span class="keyword">if</span>(word == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">char</span>[] chs = word.toCharArray();</span><br><span class="line">        TrieNode node = root;</span><br><span class="line">        node.pass++;</span><br><span class="line">        <span class="type">int</span> <span class="keyword">index</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i&lt; chs.length; i++)&#123;</span><br><span class="line">            <span class="keyword">index</span> = chs[i] - <span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">            <span class="keyword">if</span>(node.nexts[<span class="keyword">index</span>] == <span class="keyword">null</span>)&#123;</span><br><span class="line">                node.nexts[<span class="keyword">index</span>] = <span class="built_in">new</span> TrieNode();</span><br><span class="line">            &#125;</span><br><span class="line">            node = node.nexts[<span class="keyword">index</span>];</span><br><span class="line">            node.<span class="keyword">end</span>++;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    //word这个单词之前加入过几次</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> <span class="keyword">search</span>(String word)&#123;</span><br><span class="line">        <span class="keyword">if</span>(word == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">char</span>[] chs = word.toCharArray();</span><br><span class="line">        TrieNode node = root;</span><br><span class="line">        <span class="type">int</span> <span class="keyword">index</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; chs.length;i++)&#123;</span><br><span class="line">            <span class="keyword">index</span> = chs[i] - <span class="string">&#x27;a&#x27;</span>;//字符变量<span class="string">&#x27;a&#x27;</span>在做算数运算的时候，会被当成整型变量处理。<span class="string">&#x27;a&#x27;</span> = <span class="number">97</span>,这里用一个字符-<span class="string">&#x27;a&#x27;</span>,正好是TrieNode申请的数组的长度。数组的每一个下标代表一个字母。这里 字符 - <span class="string">&#x27;a&#x27;</span> 的结果正好是数组中这个字符的下标。</span><br><span class="line">            <span class="keyword">if</span>(node.nexts[<span class="keyword">index</span>] == <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            node = node.nexts[<span class="keyword">index</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> node.<span class="keyword">end</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    //所有加入的字符串中，有几个是以pre这个字符串作为前缀的</span><br><span class="line">    <span class="built_in">public</span> <span class="type">int</span> prefixNumber(String pre)&#123;</span><br><span class="line">        <span class="keyword">if</span>(pre == <span class="keyword">null</span>)&#123;</span><br><span class="line">            <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="type">char</span>[] chs = pre.toCharArray();</span><br><span class="line">        TrieNode node = root;</span><br><span class="line">        <span class="type">int</span> <span class="keyword">index</span> = <span class="number">0</span>;</span><br><span class="line">        <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; chs.length;i++)&#123;</span><br><span class="line">            <span class="keyword">index</span> = chs[i] - <span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">            <span class="keyword">if</span>(node.nexts[<span class="keyword">index</span>] == <span class="keyword">null</span>)&#123;</span><br><span class="line">                <span class="keyword">return</span> <span class="number">0</span>;</span><br><span class="line">            &#125;</span><br><span class="line">            node = node.nexts[<span class="keyword">index</span>];</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> node.pass;</span><br><span class="line">    &#125;</span><br><span class="line">    //删除</span><br><span class="line">    <span class="built_in">public</span> <span class="type">void</span> <span class="keyword">delete</span>(String word)&#123;</span><br><span class="line">        <span class="keyword">if</span>(<span class="keyword">search</span>(word) != <span class="number">0</span>)&#123;</span><br><span class="line">            <span class="type">char</span>[] chs = word.toCharArray();</span><br><span class="line">            TrieNode node = root;</span><br><span class="line">            node.pass<span class="comment">--;</span></span><br><span class="line">            <span class="type">int</span> <span class="keyword">index</span> = <span class="number">0</span>;</span><br><span class="line">            <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i &lt; chs.length; i++)&#123;</span><br><span class="line">                <span class="keyword">index</span> = chs[i] - <span class="string">&#x27;a&#x27;</span>;</span><br><span class="line">                <span class="keyword">if</span>(<span class="comment">--node.nexts[index].pass == 0)&#123;</span></span><br><span class="line">                    node.nexts[<span class="keyword">index</span>] = <span class="keyword">null</span>;</span><br><span class="line">                    <span class="keyword">return</span>;</span><br><span class="line">                &#125;</span><br><span class="line">                node = node.nexts[<span class="keyword">index</span>];</span><br><span class="line">            &#125;</span><br><span class="line">            node.<span class="keyword">end</span><span class="comment">--;</span></span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


















































      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/31/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%B8%80/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/31/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%B8%80/" class="post-title-link" itemprop="url">算法笔记(一)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-31 10:24:12" itemprop="dateCreated datePublished" datetime="2022-03-31T10:24:12+08:00">2022-03-31</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-04-06 17:10:42" itemprop="dateModified" datetime="2022-04-06T17:10:42+08:00">2022-04-06</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="算法基础"><a href="#算法基础" class="headerlink" title="算法基础"></a><strong>算法基础</strong></h1><h2 id="计数排序和基数排序-O-N"><a href="#计数排序和基数排序-O-N" class="headerlink" title="计数排序和基数排序 O(N)"></a><strong>计数排序和基数排序</strong> O(N)</h2><p>计数排序：对每一个输人元素x，确定小于x 的元素个数。 利用这一信息，就 可以直接把x放到它在输出数组中的位置上了。 例如，如果有17个元素小于x，则x就应该在第18个输出位置上。 当有几个元素相同时，这一方案要略做修改。 因为不能把它们放在同一个输出位置上。.</p>
<p>例如:对年龄进行统计，年龄一般是分布在0-200之间，申请一块200的数组，遍历需要排序的数组，将不同位置的数依次遍历，将遍历到的数与申请的数组的坐标进行对应并对其坐标位置上的数做++操作。遍历完成后，对申请的这个数组再进行遍历，遍历过程中对其进行排序。</p>
<p>基数排序：只对正整数有效，<strong>桶排序</strong></p>
<ol>
<li>先按个位数进行排序</li>
<li>在第一步的基础上，按十位数进行排序</li>
<li>在第二步的基础上，按百位数进行排序</li>
</ol>
<p>这样，最大值有多少位数，就执行多少轮。最重要的是：每一轮结束时，一定要更新列表，然后下一轮排序是在这个的基础上进行的</p>
<h2 id="基于比较的算法和不基于比较的算法"><a href="#基于比较的算法和不基于比较的算法" class="headerlink" title="基于比较的算法和不基于比较的算法"></a><strong>基于比较的算法和不基于比较的算法</strong></h2><p>只和两个数比大小有关的排序，是基于比较的排序算法，不是两个数比大小的排序，是不基于比较的排序</p>
<p>基于比较的算法有：选择、冒泡、插入、归并、快排、堆</p>
<p>时间复杂度分别为O(n^2)、O(n^2)、O(n^2)、O(n<em>logn)、O(n</em>logn)、O(n*logn)</p>
<p>空间复杂度分别为O(1)、O(1)、O(1)、O(N)、O(logn)、O(1)</p>
<p>稳定性分别为不稳定、稳定、稳定、稳定、不稳定、不稳定</p>
<p>不基于比较的排序：计数排序、基数排序等基于桶排序的算法都是不基于比较的排序</p>
<h2 id="排序算法中常见的坑"><a href="#排序算法中常见的坑" class="headerlink" title="排序算法中常见的坑"></a><strong>排序算法中常见的坑</strong></h2><ol>
<li><p>归并排序的额外空间复杂度可以变成0(1)，但是非常难，不需要掌握(因为既然需要将空间复杂度变为O(1)，直接用堆排序就OK了)，有兴趣可以搜”归并排序 内存缓存法”，但是变完之后不再稳定</p>
</li>
<li><p>“原地归并排序”的帖子更垃圾(因为这样会让时间复杂度变为O(N^2)，既然这样那直接用插入排序就OK了)</p>
</li>
<li><p>快速排序可以做到稳定性的问题，但是非常难，不需要掌握(因为这样会让空间复杂度变为O(N)，直接用归并就OK了)，可以搜”01 stable sort”</p>
</li>
<li><p>所有的改进都不重要，因为目前没找到时间复杂度O(N*logN)，额外空间复杂度O(1),又稳定的排序</p>
</li>
<li><p>有一道题目，是奇数放在数组左边，偶数放在数组右边，还要求原始的相对次序不变，碰到这个问题，可以怼面试官(经典的快排就是01标准，大于某个数的放左边，小于某个数的放右边，要么0要么1。这个题跟快排类似，奇数放左边，偶数放右边。但是，经典快排做不到稳定性)</p>
</li>
</ol>
<h2 id="算法汇总"><a href="#算法汇总" class="headerlink" title="算法汇总"></a><strong>算法汇总</strong></h2><p>稳定性：排完序之后，相同的元素之间的次序不变</p>
<p>例如：(class,age)这个表，先对age进行排序，排序后再对class进行排序，如果排序完后，每个class里的age都是从小到大(从大到小)，就说明这种第二次排序所用的排序算法是稳定的</p>
<p>具有稳定性的排序：冒泡、插入、归并、一切桶思想的排序</p>
<p>不具备稳定性的排序：选择排序、快速排序、堆排序</p>
<p>基于比较的排序，能不能做到时间复杂度在O(N*logN)以下——&gt;目前没找到</p>
<p>时间复杂度在O(N*logN)，并且空间复杂度在O(N)以下，还能做到稳定——&gt;目前没找到</p>
<h2 id="排序算法的选择"><a href="#排序算法的选择" class="headerlink" title="排序算法的选择"></a><strong>排序算法的选择</strong></h2><p>首先考虑快速排序，因为是最快速的排序。能用快排就用快排</p>
<p>如果实在是有空间的限制，很轻易就超出空间限制，则选择堆排序</p>
<p>如果需要做到稳定性，则可以选择归并排序</p>
<p>总结：</p>
<p>归并的劣势是空间复杂度较高，优势是稳定性能做到</p>
<p>快排的优势是它的常数项低，实际跑的时候是最快的排序。但劣势是空间复杂度没有办法做到O(1)，稳定性也无法做到</p>
<p>堆排的优势是它的空间使用很低，劣势是稳定性无法做到</p>
<h2 id="工程上对排序的一些改进"><a href="#工程上对排序的一些改进" class="headerlink" title="工程上对排序的一些改进"></a><strong>工程上对排序的一些改进</strong></h2><p>1) 充分利用O(N<em>logN)和O(N^2)排序<em>*各自</em></em>的优势</p>
<pre><code>+ 例如可以在快排分成两部分进行排序的时候，如果有一部分样本量比较小，可以直接用插入排序进行。叫做综合排序，也就是说在排序过程中又用了其他类型的排序。
</code></pre><p>2) 稳定性的考虑</p>
<h2 id="比较器的使用"><a href="#比较器的使用" class="headerlink" title="比较器的使用"></a><strong>比较器的使用</strong></h2><p>1) 比较器的实质是重载比较运算符</p>
<p>2) 比较器可以很好的应用在特殊标准的排序中</p>
<p>3) 比较器可以很好的应用在根据特殊标准排序的结构上</p>
<p>自定义比较器需要实现Comparator<Object>接口，实现里面的方法。</Object></p>
<img src="/wang-cheng/2022/03/31/%E7%AE%97%E6%B3%95%E7%AC%94%E8%AE%B0-%E4%B8%80/%E6%AF%94%E8%BE%83%E5%99%A8.png" class title="比较器">
<h2 id="链表"><a href="#链表" class="headerlink" title="链表"></a><strong>链表</strong></h2><h3 id="哈希表"><a href="#哈希表" class="headerlink" title="哈希表"></a><strong>哈希表</strong></h3><ol>
<li><p>哈希表在使用层面可以理解为一种集合结构</p>
</li>
<li><p>如果只有key，没有伴随数据value，可以使用HashSet结构</p>
</li>
<li><p>如果既有key又有value，可以使用HashMap</p>
</li>
<li><p>有无伴随数据，是HashMap和HashSet的唯一区别，底层的实际结构是一样的</p>
</li>
<li><p>使用哈希表增(put)、删(remove)、改(put)、查(get)的操作，可以认为时间复杂度为O(1)，但是常数时间比较大</p>
</li>
<li><p>放入哈希表中的东西，如果是基础类型，内部按值传递，内存占用就是这个东西的大小</p>
</li>
<li><p>放入哈希表中的东西，如果不是基础类型，内部按引用传递，内存占用是这个东西内存地址的大小</p>
</li>
</ol>
<h3 id="有序表"><a href="#有序表" class="headerlink" title="有序表"></a><strong>有序表</strong></h3><ol>
<li><p>有序表在使用层面上可以理解为一种集合结构</p>
</li>
<li><p>如果只有key，没有伴随数据value,可以使用TreeSet结构</p>
</li>
<li><p>如果既有key又有value，可以使用TreeMap结构</p>
</li>
<li><p>有无伴随是TreeSet和TreeMap唯一的区别，底层实际结构是一样的</p>
</li>
<li><p>有序表和哈希表的区别是，有序表把key按照顺序组织起来，而哈希表完全不组织</p>
</li>
<li><p>红黑树、AVL树、size-balance-tree和跳表等都属于有序表结构，只是底层具体实现不同</p>
</li>
<li><p>放入有序表中的东西，如果是基础类型，内部按值传递，内存占用就是这个东西的大小</p>
</li>
<li><p>放入有序表中的东西，如果不是基础类型，内部提供比较器，内部按引用传递，内存占用是这个东西内存地址的大小</p>
</li>
<li><p>不管是什么底层底层具体实现，只要是有序表，都有以下固定的基本功能和固定的时间复杂度</p>
<ul>
<li><p>void put(K key,V value)</p>
</li>
<li><p>V get(K key)</p>
</li>
<li><p>void remove(K key)</p>
</li>
<li><p>boolean containsKey(K key)</p>
</li>
<li><p>K firstKey()</p>
</li>
<li><p>K lastKey()</p>
</li>
<li><p>K floorKey(K key):如果表中存入过key，返回key，否则返回所有键值的排序结果中，key的前一个</p>
</li>
<li><p>K ceilingKey(K key):如果表中存入过key，返回key，否则返回所有键值的排序结果中，key的后一个</p>
</li>
</ul>
</li>
</ol>
<p>以上所有操作时间复杂度都是O(logN),N为有序表含有的记录数</p>
<h3 id="搜索二叉树的删除"><a href="#搜索二叉树的删除" class="headerlink" title="搜索二叉树的删除"></a><strong>搜索二叉树的删除</strong></h3><p>搜索二叉树的查找、添加都很好解决，但是删除的时候会遇到下面三种情况</p>
<p>要删除的节点是叶节点————直接删除</p>
<p>要删除的节点只有一个子节点————直接将该节点的父节点指向该节点的子节点</p>
<p>要删除的节点有两个子节点————拿左树最右侧节点替换(将左节点给这个节点的父节点)/拿右树最左测节点替换(将左节点给这个节点的父节点)</p>
<h3 id="红黑树"><a href="#红黑树" class="headerlink" title="红黑树"></a><strong>红黑树</strong></h3><ol>
<li><p>每一个节点，不是红就是黑</p>
</li>
<li><p>红黑树中的叶节点，指的是最底层的空节点</p>
</li>
<li><p>根节点和叶节点都是黑</p>
</li>
<li><p>任何两个红节点不能相邻</p>
</li>
<li><p>从某一个头部cur出发到它叶节点的每一条路径，要求黑节点数量一样</p>
</li>
</ol>
<h3 id="链表解题的方法论"><a href="#链表解题的方法论" class="headerlink" title="链表解题的方法论"></a><strong>链表解题的方法论</strong></h3><ol>
<li><p>对于笔试，不用太在乎空间复杂度，一切为了时间复杂度</p>
</li>
<li><p>对于面试，时间复杂度依然放在第一位，但是一定要找到空间最省的方法</p>
</li>
</ol>
<p>也就是说链表的题在笔试的时候，空间复杂度不考虑，只要实现这个算法就OK，面试的时候，尽量不要使用额外变量，只用有限几个变量实现算法。</p>
<p>重要技巧：</p>
<ol>
<li><p>额外数据结构(哈希表等)</p>
</li>
<li><p>快慢指针(快指针走两步，慢指针走一步)</p>
</li>
</ol>
<hr>
<p><strong>接下来是利用有限变量来对解决链表问题</strong></p>
<p>单链表有环无环的判断:利用快慢指针</p>
<ul>
<li>如果指针在循环过程中指向null，则无环</li>
<li>如果快慢指针相遇，让快指针回到起始位置，然后变成慢指针继续循环，直到两个指针再次相遇，就是入环节点。</li>
</ul>
<hr>
<p>判断链表是否为回文链表：</p>
<p>笔试遇到，直接放入栈</p>
<p>面试遇到，用快慢指针</p>
<ol>
<li><p>快指针走两步，慢指针走一步，当快指针走到尾部，慢指针走到中间</p>
</li>
<li><p>从慢指针到尾部进行一个逆序，中间位置指向空。</p>
</li>
<li><p>用两个引用记住链表的头部和尾部，然后两个引用同时往中间走，直到走到中间，在这个过程中如果有一点不一样，则不是回文。</p>
</li>
<li><p>判断完成以后再把链表还原回去。</p>
</li>
</ol>
<hr>
<p>给定一个数将链表调整为左边小、中间相等、右边大的形式：</p>
<p>笔试遇到，将单链表每一个节点放到数组中，然后进行一次快排，然后再将数组串起来</p>
<p>面试遇到，使用6个变量就可以实现</p>
<ol>
<li><p>SH、ST、EH、ET、bH、bT，分别表示小于部分的头、小于部分的尾，等于部分的头、等于部分的尾、大于部分的头、大于部分的尾</p>
</li>
<li><p>遍历链表，对每一个节点</p>
<ul>
<li>如果小于给定的数，判断SH是否为空<ul>
<li>如果为空，则SH、ST都指向这个节点,</li>
<li>如果不为空，则ST.next = node; ST = node;</li>
</ul>
</li>
<li>如果大于给定的数，判断bH是否为空<ul>
<li>如果为空，则bH、bS都指向这个节点</li>
<li>如果不为空，则bT.next = node; bT = node;</li>
</ul>
</li>
<li>如果等于给定的数，与上面两者类似操作</li>
</ul>
</li>
<li>判断小于区域、大于区域、等于区域是否为null，不为null就给他们相连，为null则忽略调为null的区域，将不为null的区域想来你。相连原则为小于区域的尾部连等于区域的头部。等于区域的尾部连大于区域的头部</li>
</ol>
<p>复制含有随机指针节点的链表问题：</p>
<p>单链表中新增一个特殊指针，可能指向链表中任意一个节点，也可能指向null</p>
<p>笔试遇到：用哈希表Map<Node,Node>来做，遍历链表，Key存放老节点，value存放克隆出来的节点。遍历老链表，用遍历到的节点查出新链表，进行next指针和特殊指针的相连。</Node,Node></p>
<p>面试遇到：遍历链表，为每一个节点复制一个新的节点，并让节点指向新节点，然后新节点指向下一个节点。这样节点与新节点也会出现像Map结构中的对应关系。然后进行新链表的建立，最后将新链表从链表中分离出来。</p>
<p>判断两条链表相交问题:</p>
<ol>
<li><p>两条链表都无环，遍历两条链表找到两条链表的尾部，并记录下链表的长度len1、len2</p>
<ul>
<li>如果尾部不相等，则两条链表不相等</li>
<li>如果尾部相等,Math.abs(len1-len2),并让更长的链表的指针先走这个绝对值，然后两条链表共同往下遍历，当两条链表遍历到的值相等时，说明是相交点</li>
</ul>
</li>
<li><p>一条有环一条无环，则两条链表不可能相交</p>
</li>
<li><p>两条链表都有环，则有三种情况</p>
<ul>
<li>两条链表不相交<ul>
<li>根据情况1判断链表的尾部是否相等就可以判断</li>
</ul>
</li>
<li>相交处就是环的入口<ul>
<li>通过单链表有环无环的判断，可以找出两个链表的入环节点，如果两个链表的入环节点相同，则证明是这种情况。那么这个时候便可以看作是第一种情况下的第二种假设，即尾部相等，让更长的链表的指针先走一个绝对值，然后共同遍历找出相交点。</li>
</ul>
</li>
<li>在环上两个位置相交——在不同地点入环<ul>
<li>通过单链表有环无环的判断，可以找出两个链表的入环节点，如果两个链表的入环节点不相同，则证明是这种情况。那么这个时候其实可以直接返回任意一个链表的入环节点，因为这两个节点都是都是相交节点。</li>
</ul>
</li>
</ul>
</li>
</ol>
<h2 id="二叉树"><a href="#二叉树" class="headerlink" title="二叉树"></a><strong>二叉树</strong></h2><h3 id="非递归遍历二叉树"><a href="#非递归遍历二叉树" class="headerlink" title="非递归遍历二叉树"></a><strong>非递归遍历二叉树</strong></h3><p>利用栈的性质</p>
<p>先序遍历</p>
<ol>
<li><p>将根节点放入栈中。然后弹出，打印(处理)该节点，然后先将右节点放入栈，再将左节点放入栈</p>
</li>
<li><p>从栈中弹出一个节点，打印(处理)该节点，然后先将右节点放入栈，再将左节点放入栈</p>
</li>
<li><p>重复第二步，如果左右节点都没有，则处理完节点后什么也不做。</p>
</li>
</ol>
<p>后序遍历</p>
<p>准备两个栈，一个收集栈，一个回收栈</p>
<ol>
<li><p>从根节点开始，放入收集栈</p>
</li>
<li><p>弹出收集栈中的一个，放入回收栈。再将这个节点的左节点、右节点分别放入收集栈</p>
</li>
<li><p>重复第二步</p>
</li>
</ol>
<p>中序遍历</p>
<p>每棵子树，整棵树左边界进栈，依次弹出的过程中，打印，然后对每个节点的右树，周而复始</p>
<h3 id="如何判断一棵二叉树是否是搜索二叉树"><a href="#如何判断一棵二叉树是否是搜索二叉树" class="headerlink" title="如何判断一棵二叉树是否是搜索二叉树"></a><strong>如何判断一棵二叉树是否是搜索二叉树</strong></h3><p>搜索二叉树的左树节点都比它小，右树都比它大</p>
<p>一棵搜索二叉树，用中序遍历是一定会升序排序的。</p>
<p>用中序遍历，如果发现它总是在升序，那么它肯定是搜索二叉树，如果某一个节点不是升序，那么就不是搜索二叉树。</p>
<ol>
<li><p>利用中序遍历递归，每次进入方法都先进行终止条件的判断(node == null)，达到终止条件则返回true</p>
</li>
<li><p>没有达到终止条件，则递归进入左节点。用一个值接收递归左节点返回来的值</p>
</li>
<li><p>如果返回true,则判断当前节点与左子节点的右子节点的值谁大，如果当前节点小于preValue(左孩子的右孩子的节点的值),返回false</p>
</li>
</ol>
<p>4.如果当前节点大于preValue(左孩子的右孩子的节点的值)，就将当前节点的值设置为preValue</p>
<ol>
<li>然后递归进当前节点的右子树查找，将递归的返回值作为返回值进行返回</li>
</ol>
<p><strong>用下面的套路解决</strong></p>
<p>当前节点为X</p>
<p>条件：</p>
<ol>
<li><p>左子树是搜索二叉树</p>
</li>
<li><p>右子树是搜索二叉树</p>
</li>
<li><p>左子树&lt;节点X</p>
</li>
<li><p>右子树&gt;节点X</p>
</li>
</ol>
<p>思考左右子树各需要给你什么信息</p>
<ol>
<li><p>左边是搜索二叉树，且给我最大值</p>
</li>
<li><p>右边是搜索二叉树，且给我最小值</p>
</li>
</ol>
<p>由于左子树要求跟右子树要求不一样，又因为递归要求的是返回是一样的，所以这里将他们统一一下，一律返回三个信息(是否是搜索二叉树，整棵树最小值是谁，整棵树最大值是谁)</p>
<hr>
<figure class="highlight processing"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">class</span> <span class="title class_">ReturnData</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> isBST;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="built_in">min</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="built_in">max</span>;</span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">ReturnData</span>(<span class="type">boolean</span> is,<span class="type">int</span> mi,<span class="type">int</span> ma)&#123;</span><br><span class="line">        isBST = is;</span><br><span class="line">        <span class="built_in">min</span> = mi;</span><br><span class="line">        <span class="built_in">max</span> = ma;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> ReturnData <span class="title function_">process</span>(Node x)&#123;</span><br><span class="line">    <span class="keyword">if</span>(x == <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ReturnData leftData = <span class="title function_">process</span>(x.<span class="property">left</span>);</span><br><span class="line">    ReturnData rightData = <span class="title function_">process</span>(x.<span class="property">right</span>);</span><br><span class="line">    <span class="type">int</span> <span class="built_in">min</span> = x.<span class="property">value</span>;</span><br><span class="line">    <span class="type">int</span> <span class="built_in">max</span> = x.<span class="property">value</span>;</span><br><span class="line">    <span class="keyword">if</span>(leftData != <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="built_in">min</span> = Math.<span class="property">min</span>(<span class="built_in">min</span>,leftData.<span class="property">min</span>);</span><br><span class="line">        <span class="built_in">max</span> = Math.<span class="property">max</span>(<span class="built_in">max</span>,leftData.<span class="property">max</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(rightData != <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="built_in">min</span> = Math.<span class="property">min</span>(<span class="built_in">min</span>,rightData.<span class="property">min</span>);</span><br><span class="line">        <span class="built_in">max</span> = Math.<span class="property">max</span>(<span class="built_in">max</span>,rightData.<span class="property">max</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="type">boolean</span> BST = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span>(leftData != <span class="literal">null</span> &amp;&amp; (!leftData.<span class="property">isBST</span> || leftData.<span class="property">max</span> &gt;= x.<span class="property">value</span>))&#123;</span><br><span class="line">        isBST = <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(leftData != <span class="literal">null</span> &amp;&amp; (!leftData.<span class="property">isBST</span> || x.<span class="property">value</span> &gt;= rightData.<span class="property">min</span> ))&#123;</span><br><span class="line">        isBST <span class="literal">false</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new </span><span class="class title_">ReturnData</span>(isBST,<span class="built_in">min</span>,<span class="built_in">max</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>
<h3 id="如何判断一棵二叉树是完全二叉树"><a href="#如何判断一棵二叉树是完全二叉树" class="headerlink" title="如何判断一棵二叉树是完全二叉树"></a><strong>如何判断一棵二叉树是完全二叉树</strong></h3><ol>
<li><p>宽度优先遍历(队列)过程中，如果某一个节点有右节点没有左节点，直接返回false</p>
</li>
<li><p>在不违背1的条件下，如果遇到了第一个左右孩子不全的情况，那么接下来遇到的所有节点，都必须是叶节点。</p>
</li>
</ol>
<h3 id="如何判断一棵二叉树是否是满二叉树"><a href="#如何判断一棵二叉树是否是满二叉树" class="headerlink" title="如何判断一棵二叉树是否是满二叉树"></a><strong>如何判断一棵二叉树是否是满二叉树</strong></h3><p>用套路来解决：</p>
<p>封装数据</p>
<ol>
<li><p>整棵树的高度</p>
</li>
<li><p>树的节点个数</p>
</li>
</ol>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">static</span> <span class="keyword">class</span> <span class="title class_">Info</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> height;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> nodes;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">Info</span><span class="params">(<span class="type">int</span> h,<span class="type">int</span> n)</span></span>&#123;</span><br><span class="line">        height = h;</span><br><span class="line">        nodes = n;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> Info <span class="title">f</span><span class="params">(Node x)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(x == null)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Info</span>(<span class="number">0</span>,<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    Info leftData = <span class="built_in">f</span>(x.left);</span><br><span class="line">    Info rightData = <span class="built_in">f</span>(x.right);</span><br><span class="line">    <span class="type">int</span> height = Math.<span class="built_in">max</span>(leftData.height,rightData.height)+<span class="number">1</span>;</span><br><span class="line">    <span class="type">int</span> nodes = leftData.nodes + rightData.nodes + <span class="number">1</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Info</span>(height,nodes);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h3 id="如何判断一棵二叉树是否是平衡二叉树-二叉树题目套路"><a href="#如何判断一棵二叉树是否是平衡二叉树-二叉树题目套路" class="headerlink" title="如何判断一棵二叉树是否是平衡二叉树(二叉树题目套路)"></a><strong>如何判断一棵二叉树是否是平衡二叉树(二叉树题目套路)</strong></h3><p>平衡二叉树：它左树的高度和它右树的高度的差都不超过1</p>
<p>如果以X为根节点进行判断</p>
<ol>
<li>X的左子树必须是平衡二叉树</li>
<li>X的右子树必须是平衡二叉树</li>
<li>两个子树的高度差不超过1</li>
</ol>
<p>思考左树和右树到底需要给你什么样的信息：</p>
<ol>
<li>是否是平的</li>
<li>高度是多少</li>
</ol>
<p>需要两个信息，则返回值需要俩值(用一个类封装两个信息)</p>
<ol>
<li><p>如果是空树，返回(是平衡二叉树，高度是0)这样的结构体</p>
</li>
<li><p>递归左子树和右子树。保存两个递归较大的那个高度+1</p>
</li>
<li><p>是否是平衡树由上面三个条件必须都成立才可以是平衡树。</p>
</li>
<li><p>返回(是否是平衡二叉树,高度是多少)</p>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> <span class="type">boolean</span> <span class="title">isBalanced</span><span class="params">(Node head)</span></span>&#123;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">process</span>(head).isBalanced;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="type">static</span> <span class="keyword">class</span> <span class="title class_">ReturnType</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">boolean</span> isBalanced;</span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> height;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">ReturnType</span><span class="params">(<span class="type">boolean</span> isB,<span class="type">int</span> hei)</span></span>&#123;</span><br><span class="line">        isBalanced = isB;</span><br><span class="line">        height = hei;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> ReturnType <span class="title">process</span><span class="params">(Node x)</span></span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(x == null)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">ReturnType</span>(<span class="literal">true</span>,<span class="number">0</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    ReturnType leftData = <span class="built_in">process</span>(x.left);</span><br><span class="line">    ReturnType rightData = <span class="built_in">process</span>(x.right);</span><br><span class="line">    <span class="type">int</span> height = Math.<span class="built_in">max</span>(leftData.height,rightData.height) + <span class="number">1</span>;</span><br><span class="line">    <span class="type">boolean</span> isBalanced = leftData.isBalanced &amp;&amp; rightData.isBalanced &amp;&amp; Math.<span class="built_in">abs</span>(leftData.height - rightData.height) &lt; <span class="number">2</span>;</span><br><span class="line">    <span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">ReturnType</span>(isBalanced,height); </span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br></pre></td></tr></table></figure>
</li>
</ol>
<p><strong>搜索二叉树、满二叉树、平衡二叉树都可以用这个套路</strong></p>
<p>这个套路其实就是一个树型Dp，树型Dp就是罗列所有的可能性。</p>
<p>这个套路就是动态规划，左子树给我的信息和右子树给我的信息就是他们动态规划出来的结果，我跟我他们给出的结果输出我的动态规划然后往上给。</p>
<p>只要我解决这个问题需要跟这棵树的左子树要信息并且需要跟我的右子树要信息，那么我就可以使用树型Dp。但并不是所有问题都可以用这个套路来解决。</p>
<h2 id="牛客NC102题目"><a href="#牛客NC102题目" class="headerlink" title="牛客NC102题目"></a><strong>牛客NC102题目</strong></h2><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//o1 o2 一定属于head为头的树</span></span><br><span class="line"><span class="comment">//返回o1 o2的最低公共祖先</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Node <span class="title">lca</span>(<span class="params">Node head,Node o1,Node o2</span>)</span>&#123;</span><br><span class="line">    HashMap&lt;Node,Node&gt; fatherMap = <span class="keyword">new</span> HashMap&lt;&gt;();</span><br><span class="line">    fatherMap.put(head,head);</span><br><span class="line">    process(head,fatherMap);</span><br><span class="line">    HashSet&lt;Node&gt; set1 = <span class="keyword">new</span> HashSet&lt;&gt;();</span><br><span class="line">    </span><br><span class="line">    Node cur = o1;</span><br><span class="line">    <span class="keyword">while</span>(cur != fatherMap.<span class="keyword">get</span>(cur))&#123;</span><br><span class="line">        set1.<span class="keyword">add</span>(cur);</span><br><span class="line">        cur = fatherMap.<span class="keyword">get</span>(cur);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    set1.<span class="keyword">add</span>(head);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">process</span>(<span class="params">Node head,HashMap&lt;Node,Node&gt; fatherMap</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(head == <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="literal">null</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    fatherMap.put(head.left,head);</span><br><span class="line">    fatherMap.put(head.right,head);</span><br><span class="line">    process(head.left,fatherMap);</span><br><span class="line">    process(head.right,fatherMap);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>更优解</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="type">int</span> <span class="title function_">lowestCommonAncestor</span> <span class="params">(TreeNode root, <span class="type">int</span> o1, <span class="type">int</span> o2)</span> &#123;</span><br><span class="line">    root = helper(root,o2,o1);</span><br><span class="line">    <span class="keyword">return</span> root.val;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">public</span> TreeNode <span class="title function_">helper</span><span class="params">(TreeNode root, <span class="type">int</span> o1,<span class="type">int</span> o2)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(root == <span class="literal">null</span> || root.val == o1 || root.val == o2)&#123;</span><br><span class="line">        <span class="keyword">return</span> root;</span><br><span class="line">    &#125;   </span><br><span class="line">    <span class="type">TreeNode</span> <span class="variable">node1</span> <span class="operator">=</span> helper(root.left,o1,o2);</span><br><span class="line">    <span class="type">TreeNode</span> <span class="variable">node2</span> <span class="operator">=</span> helper(root.right,o1,o2);</span><br><span class="line">    <span class="keyword">if</span>(node1 == <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> node2;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">if</span>(node2 == <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> node1;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> root;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="在二叉树中找到一个节点的后继节点"><a href="#在二叉树中找到一个节点的后继节点" class="headerlink" title="在二叉树中找到一个节点的后继节点"></a><strong>在二叉树中找到一个节点的后继节点</strong></h2><p>后继节点:中序遍历中一个节点的后一个节点</p>
<p>前驱节点:中序遍历中一个节点的前一个节点</p>
<p>求X的的后继节点</p>
<ol>
<li>X有右树的时候，X的后继就是它右树上的最左节点</li>
<li>X无右树的时候，往上找，判断当前节点是否是父节点的左节点，如果是，则父节点是后继节点。</li>
</ol>
<figure class="highlight crmsh"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">public static <span class="keyword">Node</span> <span class="title">getSuccessorNode</span>(<span class="keyword">Node</span> <span class="title">node</span>)&#123;</span><br><span class="line">    if(<span class="keyword">node</span> <span class="title">== null</span>)&#123;</span><br><span class="line">        return <span class="keyword">node</span><span class="title">;</span></span><br><span class="line"><span class="title">    &#125;</span></span><br><span class="line"><span class="title">    if</span>(node.right != null)&#123;</span><br><span class="line">        return getLeftMost(node.right);</span><br><span class="line">    &#125;else&#123;</span><br><span class="line">        //无右子树</span><br><span class="line">        <span class="keyword">Node</span> <span class="title">parent</span> = node.parent;</span><br><span class="line">        while(parent != null &amp;&amp; parent.left != <span class="keyword">node</span><span class="title">)&#123;</span></span><br><span class="line"><span class="title">            node</span> = parent;</span><br><span class="line">            parent = node.parent;</span><br><span class="line">        &#125;</span><br><span class="line">        return parent;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">public static <span class="keyword">Node</span> <span class="title">getLeftMost</span>(<span class="keyword">Node</span> <span class="title">node</span>)&#123;</span><br><span class="line">    if(<span class="keyword">node</span> <span class="title">== null</span>)&#123;</span><br><span class="line">        return <span class="keyword">node</span><span class="title">;</span></span><br><span class="line"><span class="title">    &#125;</span></span><br><span class="line"><span class="title"></span></span><br><span class="line"><span class="title">    while</span>(node.left != null)&#123;</span><br><span class="line">        <span class="keyword">node</span> <span class="title">= node</span>.left;</span><br><span class="line">    &#125;</span><br><span class="line">    return <span class="keyword">node</span><span class="title">;</span></span><br><span class="line"><span class="title">&#125;</span></span><br></pre></td></tr></table></figure>
<h2 id="字符串的序列化和反序列化"><a href="#字符串的序列化和反序列化" class="headerlink" title="字符串的序列化和反序列化"></a><strong>字符串的序列化和反序列化</strong></h2><p>序列化：对二叉树来说，就是内存里的二叉树，怎么给他变成硬盘里字符串的形式，而且这个字符串还要对应出唯一的结构。</p>
<p>也就是内存里的一棵树如何变成字符串的形式，又如何从字符串变成内存里的树</p>
<p>以什么样的方式序列化，就以什么样的方式反序列化</p>
<p>序列化的方式就是通过遍历子树，记录节点和为null的子节点。</p>
<p>如果通过先序遍历序列化二叉树，就要以先序遍历的方式反序列化回去。</p>
<p>序列化<br><figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="title class_">String</span> <span class="title function_">serialByPre</span>(<span class="params">Node head</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span>(head == <span class="literal">null</span>)&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;#_&quot;</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="title class_">String</span> res = head.<span class="property">value</span> + <span class="string">&quot;_&quot;</span>;</span><br><span class="line">    res += <span class="title function_">serialByPre</span>(head.<span class="property">left</span>);</span><br><span class="line">    res += <span class="title function_">serialByPre</span>(head.<span class="property">right</span>);</span><br><span class="line">    <span class="keyword">return</span> res;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>反序列化<br><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> Node <span class="title">reconByPreString</span><span class="params">(<span class="type">String</span> preStr)</span></span>&#123;</span><br><span class="line">    <span class="type">String</span>[] values = preStr.<span class="built_in">split</span>(<span class="string">&quot;_&quot;</span>);</span><br><span class="line">    Queue&lt;<span class="type">String</span>&gt; queue = <span class="keyword">new</span> <span class="built_in">LinkedList</span>&lt;<span class="type">String</span>&gt;();</span><br><span class="line">    <span class="keyword">for</span>(<span class="type">int</span> i = <span class="number">0</span>; i != values.length; i++)&#123;</span><br><span class="line">        queue.<span class="built_in">add</span>(values[i]);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">return</span> <span class="built_in">reconPreOrder</span>(queue);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="type">static</span> Node <span class="title">reconPreOrder</span><span class="params">(Queue&lt;<span class="type">String</span>&gt; queue)</span></span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="type">String</span> value = queue.<span class="built_in">poll</span>();</span><br><span class="line">    <span class="keyword">if</span>(value.<span class="built_in">equals</span>(<span class="string">&quot;#&quot;</span>))&#123;</span><br><span class="line">        <span class="keyword">return</span> null;</span><br><span class="line">    &#125;</span><br><span class="line">    Node head  = <span class="keyword">new</span> <span class="built_in">Node</span>(Integer.<span class="built_in">valueOf</span>(value));</span><br><span class="line"></span><br><span class="line">    head.left = <span class="built_in">reconPreOrder</span>(queue);</span><br><span class="line">    head.right = <span class="built_in">reconPreOrder</span>(queue);</span><br><span class="line">    <span class="keyword">return</span> head;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="微软原题"><a href="#微软原题" class="headerlink" title="微软原题"></a><strong>微软原题</strong></h2><p>请把一张纸条竖着放在桌子上，然后从纸条的下边向上方对折1次，压出折痕后展开。</p>
<p>此时折痕是凹下去的，即折痕突起的方式指向纸条的背面。</p>
<p>如果从纸条的下边向上方连续对折2次，压出折痕后展开，此时有三条折痕，从上到下依次是下折痕、下折痕、上折痕。</p>
<p>给定一个输入参数N，代表纸条都从下边向上方连续对折N次。</p>
<p>请从上到下打印所有折痕的方向。</p>
<p>分析:通过实际操作得出，第一次的折痕是凹折痕，第二次对折后，在第一次对折的上方的折痕是凹折痕，下方是凸折痕。分别记为凹2和凸2。继续对折，会在凹2的上方出现凹折痕，在下方出现凸折痕；会在凸2的上方出现凹折痕，凸2的下方出现凸折痕。</p>
<p>由此可以得出:此规律可以写成一个二叉树，根节点为第一次对折出来的折痕。左子树为凹折痕，右子树为凸折痕。其子树也具有这样的规律</p>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public static void print<span class="constructor">AllFolds(<span class="params">int</span> N)</span>&#123;</span><br><span class="line">    <span class="comment">//1 ，true 代表第一个节点，且为凹</span></span><br><span class="line">    print<span class="constructor">Process(1,N,<span class="params">true</span>)</span>;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">//递归过程中，来到了某一个节点</span></span><br><span class="line"><span class="comment">//i是节点的层数，N一共的层数，down == true 凹 ， down == false 凸</span></span><br><span class="line">public static void print<span class="constructor">Process(<span class="params">int</span> <span class="params">i</span>,<span class="params">int</span> N,<span class="params">boolean</span> <span class="params">down</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(i &gt; N)&#123;</span><br><span class="line">        return;</span><br><span class="line">    &#125;</span><br><span class="line">    print<span class="constructor">Process(<span class="params">i</span>+1,N,<span class="params">true</span>)</span>;</span><br><span class="line">    <span class="module-access"><span class="module"><span class="identifier">System</span>.</span></span>out.println(down ? <span class="string">&quot;凹&quot;</span> : <span class="string">&quot;凸&quot;</span>);</span><br><span class="line">    print<span class="constructor">Process(<span class="params">i</span>+1,N,<span class="params">false</span>)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/26/%E7%AE%97%E6%B3%95%E4%B8%93%E9%A2%98/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/26/%E7%AE%97%E6%B3%95%E4%B8%93%E9%A2%98/" class="post-title-link" itemprop="url">算法专题</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-26 19:17:51" itemprop="dateCreated datePublished" datetime="2022-03-26T19:17:51+08:00">2022-03-26</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-03-27 13:58:34" itemprop="dateModified" datetime="2022-03-27T13:58:34+08:00">2022-03-27</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="排序算法篇"><a href="#排序算法篇" class="headerlink" title="排序算法篇"></a><strong>排序算法篇</strong></h1><h2 id="插入排序"><a href="#插入排序" class="headerlink" title="插入排序"></a><strong>插入排序</strong></h2><p>插入排序，一般也称为直接插入排序。</p>
<p>对于少量元素的排序，它是一个有效的算法。</p>
<p>假设前面n-1个数已经是排好顺序的，现将第n个数插到前面已经排好的顺序中，然后找到适合自己的位置，使得插入第n个数的这个序列也是排好顺序的</p>
<p>按照此法对所有元素进行插入，直到整个序列排为有序的过程，称为插入排序</p>
<p>插入排序的平均时间复杂度也是O(n^2)，空间复杂度为常数阶O(1)，具体时间复杂度和数组的有序性也是有关联的。最优情况的时间复杂度为O(n)，最坏情况时间复杂度为O(n^2)</p>
<p>从小到大的插入排序算法</p>
<figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">public class InsertionSort &#123;</span><br><span class="line">    public static void sort(int[] arr)&#123;</span><br><span class="line">        int n <span class="operator">=</span> arr.length<span class="comment">;</span></span><br><span class="line">        int temp <span class="operator">=</span> <span class="number">0</span><span class="comment">;</span></span><br><span class="line">        for(int i <span class="operator">=</span> <span class="number">0</span><span class="comment">;i &lt; n; i++)&#123;</span></span><br><span class="line">            //寻找元素arr[i]合适的插入位置</span><br><span class="line">            for(int j <span class="operator">=</span> i<span class="comment">;j &gt; 0;j--)&#123;</span></span><br><span class="line">                if(arr[i] &lt; arr[i-<span class="number">1</span>])&#123;</span><br><span class="line">                    temp <span class="operator">=</span> arr[i-<span class="number">1</span>]<span class="comment">;</span></span><br><span class="line">                    arr[i-<span class="number">1</span>] <span class="operator">=</span> arr[i]<span class="comment">;</span></span><br><span class="line">                    arr[i] <span class="operator">=</span> temp<span class="comment">;</span></span><br><span class="line">                &#125;else</span><br><span class="line">                    berak<span class="comment">;</span></span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="希尔排序"><a href="#希尔排序" class="headerlink" title="希尔排序"></a><strong>希尔排序</strong></h2><p>希尔排序是插入排序的一种，它是针对直接插入排序算法的改进</p>
<p>希尔排序又称缩小增量排序，它通过比较相距一定间隔的元素来进行，各躺比较所用的距离随着算法的进行而减小，直到只比较相邻元素的最后一趟排序为止。</p>
<p>希尔排序时间复杂度是O(n^(1.3-2))，空间复杂度为常数阶O(1)。希尔排序没有时间复杂度为O(n(logn)) 的快速排序算法快，因此对中等大小规模表现良好，但对规模非常大的数据排序不是最优选择，总之比一般O(n^2 )复杂度的算法快得多。</p>
<figure class="highlight gradle"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> ShellSort&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="keyword">sort</span>(<span class="keyword">int</span>[] arr)&#123;</span><br><span class="line">        <span class="keyword">for</span>(<span class="keyword">int</span> gap = arr.length<span class="regexp">/2; gap &gt; 0;gap /</span>= <span class="number">2</span>)&#123;</span><br><span class="line">            <span class="keyword">for</span>(<span class="keyword">int</span> i = gap; i &lt; arr.length; i++)&#123;</span><br><span class="line">                <span class="keyword">int</span> tmp = arr[i];</span><br><span class="line">                <span class="keyword">for</span>(<span class="keyword">int</span> j = i; j &gt;= gap &amp;&amp; tmp &lt; arr[j-gap]; j -= gap)&#123;</span><br><span class="line">                    arr[j] = arr[j- gap];</span><br><span class="line">                &#125;</span><br><span class="line">                arr[j] = tmp;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>个人理解：</p>
<p>第一个for循环是逐步缩小增量</p>
<p>第二个for循环是依次从第一个增量处开始遍历整个数组</p>
<p>tmp的记录i下标的值，这个值是可能需要调整的值，所以用tmp暂存下来。当调整的时候只需要将比这个值大的数放到这个下标所在的位置就可以了</p>
<p>第三个for循环是对tmp所记录的值进行比较，所比较的数是从第i个数开始向后遍历存在于这个增量上的数。</p>
<p>arr[j] &#x3D; tmp是在比较完成后，再将tmp暂存的值赋值给j所在下标的位置(如果上一步没有进行调整，则tmp与arr[j]的值是相同的，也就是说又将i下标的值放回原处了)</p>
<h2 id="选择排序"><a href="#选择排序" class="headerlink" title="选择排序"></a><strong>选择排序</strong></h2><p>选择排序是一种简单直观的排序算法。其基本思想是:首先在未排序的数列中找到最小(大)元素，然后将其存放到数列的起始位置；接着，再从剩余未排序的元素中继续寻找最小(大)元素，然后放到已排序序列的末尾。以此类推，直到所有元素均排序完毕</p>
<figure class="highlight excel"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">void select_sort(<span class="built_in">int</span>[] a,<span class="built_in">int</span> <span class="built_in">n</span>)&#123;</span><br><span class="line">    <span class="built_in">int</span> i;</span><br><span class="line">    <span class="built_in">int</span> j;</span><br><span class="line">    <span class="built_in">int</span> <span class="built_in">min</span>;</span><br><span class="line">    for(i = <span class="number">0</span>; i &lt; <span class="built_in">n</span>; i++)&#123;</span><br><span class="line">        <span class="built_in">min</span> = i;</span><br><span class="line">        for(j = i+<span class="number">1</span>;j &lt; <span class="built_in">n</span>;j++)&#123;</span><br><span class="line">            <span class="built_in">if</span>(a[j] &lt; a[<span class="built_in">min</span>])&#123;</span><br><span class="line">                <span class="built_in">min</span> = j;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">if</span>(<span class="built_in">min</span> != i)&#123;</span><br><span class="line">            <span class="built_in">int</span> temp = a[i];</span><br><span class="line">            a[i] = a[<span class="built_in">min</span>];</span><br><span class="line">            a[<span class="built_in">min</span>] = temp;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="冒泡排序"><a href="#冒泡排序" class="headerlink" title="冒泡排序"></a><strong>冒泡排序</strong></h2><p>冒泡排序就是每遍历一轮，都让最大(小)的数交换到最右(左)边，因为思路很简单，就不多说了，直接上代码</p>
<figure class="highlight inform7"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">void BubbleSort(int a<span class="comment">[]</span>, int len)&#123;</span><br><span class="line">    int i,j,temp;</span><br><span class="line">    for(j = 0;j &lt; len-1;j++)&#123;</span><br><span class="line">        for(i = 0; i &lt;len-1-j; i++)&#123;</span><br><span class="line">            if(a<span class="comment">[i]</span>&gt;a<span class="comment">[i+1]</span>)&#123;</span><br><span class="line">                temp = a<span class="comment">[i]</span>;</span><br><span class="line">                a<span class="comment">[i]</span> = a<span class="comment">[i+1]</span>;</span><br><span class="line">                a<span class="comment">[i+1]</span> = temp;</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<h2 id="快速排序"><a href="#快速排序" class="headerlink" title="快速排序"></a><strong>快速排序</strong></h2><p>快速排序由于排序效率在同为O(N*logN)的几种排序算法中效率较高，因此经常被采用。</p>
<p>原理：快速排序的基本思想，是通过一趟排序将待排记录分隔成独立的两部分，其中一部分记录的关键字均比另一部分的关键字小，则可分别对这两部分记录继续进行排序，以达到整个序列有序。说白了就是给基准数据找其正确索引位置的过程。</p>
<p>基本思想：</p>
<ul>
<li><p>先从数列中取出一个数作为基准数</p>
</li>
<li><p>分区过程，将比这个数大的数全部放到它的右边，小于或等于它的数全部放到它的左边</p>
</li>
<li><p>再对左右区间重复第二步，直到各区间只有一个数</p>
</li>
</ul>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line">void quick<span class="constructor">Sort(<span class="params">int</span>[] <span class="params">arr</span>,<span class="params">int</span> <span class="params">low</span>,<span class="params">int</span> <span class="params">high</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>(low &lt; high)&#123;</span><br><span class="line">        <span class="built_in">int</span> index = get<span class="constructor">Index(<span class="params">arr</span>,<span class="params">low</span>,<span class="params">high</span>)</span>;</span><br><span class="line">        quick<span class="constructor">Sort(<span class="params">arr</span>,<span class="params">low</span>,<span class="params">index</span>-1)</span>;</span><br><span class="line">        quick<span class="constructor">Sort(<span class="params">arr</span>,<span class="params">index</span>+1,<span class="params">high</span>)</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">int</span> get<span class="constructor">Index(<span class="params">int</span>[] <span class="params">arr</span>,<span class="params">int</span> <span class="params">low</span>,<span class="params">int</span> <span class="params">high</span>)</span>&#123;</span><br><span class="line">    <span class="built_in">int</span> temp = arr<span class="literal">[<span class="identifier">low</span>]</span>;</span><br><span class="line">    <span class="keyword">while</span>(low &lt; high)&#123;</span><br><span class="line">        <span class="keyword">while</span>(low &lt; high<span class="operator"> &amp;&amp; </span>arr<span class="literal">[<span class="identifier">high</span>]</span> &gt;= temp)&#123;</span><br><span class="line">            high--;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(low &lt; high)&#123;</span><br><span class="line">            arr<span class="literal">[<span class="identifier">low</span>]</span> = arr<span class="literal">[<span class="identifier">high</span>]</span>;</span><br><span class="line">            low++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">while</span>(low &lt; high<span class="operator"> &amp;&amp; </span>arr<span class="literal">[<span class="identifier">low</span>]</span> &lt; = temp)&#123;</span><br><span class="line">            low++;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">if</span>(low &lt; high)&#123;</span><br><span class="line">            arr<span class="literal">[<span class="identifier">high</span>]</span> arr<span class="literal">[<span class="identifier">low</span>]</span>;</span><br><span class="line">            high--;</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    arr<span class="literal">[<span class="identifier">low</span>]</span> = temp;</span><br><span class="line">    return low;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="归并排序"><a href="#归并排序" class="headerlink" title="归并排序"></a><strong>归并排序</strong></h2><p>归并排序是建立在归并操作上的一种有效、稳定的排序算法，该算法是采用分冶法的一个非常典型的应用。将已有序的子序列合并，得到完全有序的序列。即先使每个子序列有序，再使子序列段间有序。若将两个有序表合并成一个有序表，称为二路归并</p>
<p>归并排序的时间复杂度为O(nlogn)。归并排序时需要和待排序记录个数相等的存储空间，所以空间复杂度为O(n)。归并排序适用于数据量大，并且对稳定性有要求的场景。</p>
<img src="/wang-cheng/2022/03/26/%E7%AE%97%E6%B3%95%E4%B8%93%E9%A2%98/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F.png" class title="归并排序">

<figure class="highlight pgsql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">public</span> <span class="type">void</span> sort(<span class="type">int</span>[] arr)&#123;</span><br><span class="line">    <span class="type">int</span>[] <span class="keyword">temp</span> = <span class="built_in">new</span> <span class="type">int</span>[arr.length];</span><br><span class="line">    sort(arr,<span class="number">0</span>,arr.length<span class="number">-1</span>,<span class="keyword">temp</span>);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> <span class="type">void</span> sort(<span class="type">int</span>[] arr,<span class="type">int</span> left,<span class="type">int</span> right,<span class="type">int</span>[] <span class="keyword">temp</span>)&#123;</span><br><span class="line">    <span class="keyword">if</span>(left &lt; right)&#123;</span><br><span class="line">        <span class="type">int</span> mid = (left+right)/<span class="number">2</span>;</span><br><span class="line">        sort(arr,left,mid,<span class="keyword">temp</span>);</span><br><span class="line">        sort(arr,mid+<span class="number">1</span>,right,<span class="keyword">temp</span>);</span><br><span class="line">        merge(arr,left,mid,right,<span class="keyword">temp</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="built_in">public</span> <span class="type">void</span> merge(<span class="type">int</span>[] arr,<span class="type">int</span> left,<span class="type">int</span> mid,<span class="type">int</span> right,<span class="type">int</span>[] <span class="keyword">temp</span>)&#123;</span><br><span class="line">    <span class="type">int</span> i = left;   //左序列指针</span><br><span class="line">    <span class="type">int</span> j = mid+<span class="number">1</span>;  //右序列指针</span><br><span class="line">    <span class="type">int</span> t = <span class="number">0</span>;      //临时数组指针</span><br><span class="line">    <span class="keyword">while</span>(i &lt;= mid &amp;&amp; j &lt;= right)&#123;</span><br><span class="line">        <span class="keyword">if</span>(arr[i] &lt;= arr[j])&#123;</span><br><span class="line">            <span class="keyword">temp</span>[t++] = arr[i++];</span><br><span class="line">        &#125;<span class="keyword">else</span>&#123;</span><br><span class="line">            <span class="keyword">temp</span>[t++] = <span class="keyword">temp</span>[j++];</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">while</span>(i &lt;= mid)&#123;    //将左边剩余元素填充进<span class="keyword">temp</span>中</span><br><span class="line">        <span class="keyword">temp</span>[i++] = arr[i++]</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">while</span>(j &lt;= right)&#123;      //将右序列剩余元素填充进<span class="keyword">temp</span>中</span><br><span class="line">        <span class="keyword">temp</span>[i++] arr[j++]</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    t = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    //将<span class="keyword">temp</span>中的元素全部拷贝到原数组中</span><br><span class="line">    <span class="keyword">while</span>(left &lt;= right)&#123;</span><br><span class="line">        arr[left++] = <span class="keyword">temp</span>[t++];</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

































      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/26/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%BA%8C/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/26/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%BA%8C/" class="post-title-link" itemprop="url">做题笔记(二)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-26 18:50:39" itemprop="dateCreated datePublished" datetime="2022-03-26T18:50:39+08:00">2022-03-26</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-15 11:44:12" itemprop="dateModified" datetime="2022-05-15T11:44:12+08:00">2022-05-15</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="牛客网刷题笔记"><a href="#牛客网刷题笔记" class="headerlink" title="牛客网刷题笔记"></a><strong>牛客网刷题笔记</strong></h1><h2 id="在MySQL中Replace在相同的主键或者唯一键的时候相当于以下以下哪个操作"><a href="#在MySQL中Replace在相同的主键或者唯一键的时候相当于以下以下哪个操作" class="headerlink" title="在MySQL中Replace在相同的主键或者唯一键的时候相当于以下以下哪个操作"></a><strong>在MySQL中Replace在相同的主键或者唯一键的时候相当于以下以下哪个操作</strong></h2><p>replace具备替换拥有唯一索引或者主键索引重复数据的能力，也就是如果使用replace into插入的数据的唯一索引或者主键索引与之前的数据有重复的情况，将会删除原先的数据，然后再进行添加</p>
<h2 id="MYSQL中处理插入过程主键或唯一重复值的解决办法"><a href="#MYSQL中处理插入过程主键或唯一重复值的解决办法" class="headerlink" title="MYSQL中处理插入过程主键或唯一重复值的解决办法"></a><strong>MYSQL中处理插入过程主键或唯一重复值的解决办法</strong></h2><ol>
<li>IGNORE:有则忽略，无则插入</li>
<li>REPLACE：有则删除再插入，无则插入</li>
<li>ON DUPLIACATE KEY UPDATE:有则更新，无则插入</li>
</ol>
<h2 id="数据结构之队列"><a href="#数据结构之队列" class="headerlink" title="数据结构之队列"></a><strong>数据结构之队列</strong></h2><p>Java中的队列继承了Collection集合。</p>
<p>public interface Queue<E> extends Collection<E></E></E></p>
<p>Queue是一个接口，定义了6个方法，分别为：</p>
<ul>
<li><p>boolean add(E e):增加一个元索 如果队列已满，则抛出一个IIIegaISlabEepeplian异常</p>
</li>
<li><p>boolean offer(E e):添加一个元素并返回true 如果队列已满，则返回false</p>
</li>
<li><p>E remove():移除并返回队列头部的元素 如果队列为空，则抛出一个NoSuchElementException异常</p>
</li>
<li><p>E poll():移除并返问队列头部的元素 如果队列为空，则返回null</p>
</li>
<li><p>E element():返回队列头部的元素 如果队列为空，则抛出一个NoSuchElementException异常</p>
</li>
<li><p>E peek():返回队列头部的元素 如果队列为空，则返回null</p>
</li>
</ul>
<p>Queue是个接口，继承自Collection接口，Deque,LinkedList,PriorityQueue,BlockingQueue等类都实现了它</p>
<p>方法介绍：</p>
<ol>
<li><p>add(E),offer(E)在尾部添加</p>
<ul>
<li><p>他们的共同之处是建议实现类禁止添加null元素，否则会报空指针</p>
</li>
<li><p>不同之处在于add()方法在添加失败(比如队列已满)时会报一些运行时错误，而offer()方法即使在添加失败时也不会崩溃，只会返回false</p>
</li>
</ul>
</li>
<li><p>remove()、poll()删除并返回头部</p>
<ul>
<li>当队列为空时remove()方法会报NoSuchElementException错误，而poll()不会崩溃，只会返回null。</li>
</ul>
</li>
<li><p>element(),ppek()获取但不删除</p>
<ul>
<li>当队列为空时element会抛出异常，peek()不会崩溃，只会返回null。</li>
</ul>
</li>
</ol>
<h2 id="字符串操作"><a href="#字符串操作" class="headerlink" title="字符串操作"></a><strong>字符串操作</strong></h2><ol>
<li><p>获取字符串长度length()</p>
</li>
<li><p>获取字符串中第i个字符charAt(i)</p>
</li>
<li><p>将此字符串中的字符复制到目标字符数组中  void getChars(indexBegin,indexEnd,array,arrayBegin) </p>
<ul>
<li>indexBegin:需要复制的字符串的开始索引</li>
<li>indexEnd:需要复制的字符串的结束索引</li>
<li>array:前面定义的char型数组的数组名</li>
<li>arrayBegin:数组array开始存储的位置索引号</li>
</ul>
</li>
<li><p>按字典顺序比较两个字符串  int compareTo(String anotherString)</p>
</li>
<li><p>测试此字符串是否以指定的后缀结尾  endsWith(String suffix)</p>
</li>
<li><p>返回指定字符第一次出现的字符串内的索引 int indexOf(String str) / indexOf(String str, int fromIndex) 从指定的索引开始</p>
</li>
<li><p>返回指定字符的最后一次出现的字符串中的索引 int  lastIndexOf(int ch) / lastIndexOf(int ch, int fromIndex) 从指定的索引开始向后搜索</p>
</li>
<li><p>返回一个字符序列，该序列是该序列的子序列 CharSequence subSequence(int beginIndex, int endIndex) </p>
</li>
<li><p>返回一个字符串，该字符串是此字符串的子字符串 String substring(int beginIndex) / substring(int beginIndex, int endIndex)</p>
</li>
<li><p>将此字符串转换为新的字符数组 char[] toCharArray() </p>
</li>
<li><p>返回一个字符串，其值为此字符串，并删除任何前导和尾随空格。String trim()</p>
</li>
</ol>
<h2 id="数据结构之栈"><a href="#数据结构之栈" class="headerlink" title="数据结构之栈"></a><strong>数据结构之栈</strong></h2><p>栈继承自Vector这个类，这个类与ArrayList、LinkedList一起实现了AbstractList抽象类</p>
<p>Stack与Queue不在一个包下，Stack在java.util.AbstractCollection<E>包下，Queue在java.util包下</E></p>
<p>栈扩展了Vector的操作，构造方法只有一个无参构造</p>
<p>方法：</p>
<ol>
<li><p>boolean empty() 测试此堆栈是否为空</p>
</li>
<li><p>E peek() 查看此堆栈顶部的对象，而不从堆栈中删除它</p>
</li>
<li><p>E pop() 删除此堆栈顶部的对象，并将该对象作为此函数的返回值</p>
</li>
<li><p>E push(E item) 将项目推送至此堆栈的顶部</p>
</li>
<li><p>int search(Object o) 返回一个对象在此堆栈上的基于1的位置</p>
</li>
</ol>
<h2 id="接口中变量和方法的默认修饰符是什么"><a href="#接口中变量和方法的默认修饰符是什么" class="headerlink" title="接口中变量和方法的默认修饰符是什么"></a><strong>接口中变量和方法的默认修饰符是什么</strong></h2><p>变量: public static final </p>
<p>方法: public abstract</p>
<h2 id="可能引起进程挂起的原因有"><a href="#可能引起进程挂起的原因有" class="headerlink" title="可能引起进程挂起的原因有"></a><strong>可能引起进程挂起的原因有</strong></h2><p>（1）终端用户的请求。当终端用户在自己的程序运行期间发现有可疑问题时，希望暂停使自己的程序静止下来。亦即，使正在执行的进程暂停执行；若此时用户进 程正处于就绪状态而未执行，则该进程暂不接受调度，以便用户研究其执行情况或对程序进行修改。我们把这种静止状态称为“挂起状态”。</p>
<p>（2）父进程的请求。有时父进程希望挂起自己的某个子进程，以便考察和修改子进程，或者协调各子进程间的活动。 　　     </p>
<p>（3）负荷调节的需要。当实时系统中的工作负荷较重，已可能影响到对实时任务的控制时，可由系统把一些不重要的进程挂起，以保证系统能正常运行。</p>
<p>（4）操作系统的需要。操作系统有时希望挂起某些进程，以便检查运行中的资源使用情况或进行记账</p>
<h2 id="不同的事务交叉执行可能会破坏事务的哪一特性"><a href="#不同的事务交叉执行可能会破坏事务的哪一特性" class="headerlink" title="不同的事务交叉执行可能会破坏事务的哪一特性"></a><strong>不同的事务交叉执行可能会破坏事务的哪一特性</strong></h2><p>A 原子性 要么都执行，要么都不执行</p>
<p>C 一致性 事物执行前后数据库保持一致的正确状态</p>
<p>I 隔离性 不同事务之间互不干扰</p>
<p>D 持久性 事务一旦提交，对数据库中数据的变更是永久的</p>
<h2 id="反射方面的问题"><a href="#反射方面的问题" class="headerlink" title="反射方面的问题"></a><strong>反射方面的问题</strong></h2><p><code>getDeclaredFields()</code>方法都能获取到哪些字段？</p>
<p>获取类的字段有两种方式：getFields()和getDeclaredFields()。</p>
<p>getFields()：获得某个类的所有的公共（public）的字段，包括父类中的字段。<br>getDeclaredFields()：获得某个类的所有声明的字段，即包括public、private和proteced，但是不包括父类的声明字段。</p>
<p><strong>getDeclaredConstructors和getConstructors的区别</strong></p>
<p>getDeclaredConstructors和getConstructors都能得到默认的public构造函数</p>
<p>getDeclaredConstructors可以得到所有访问权限的构造函数；getConstructors只能得到public修饰的构造函数。</p>
<ul>
<li>构造方法有四种访问权限<ul>
<li>public</li>
<li>默认</li>
<li>protected</li>
<li>private</li>
</ul>
</li>
</ul>
<h2 id="protected、public、private作用范围"><a href="#protected、public、private作用范围" class="headerlink" title="protected、public、private作用范围"></a><strong>protected、public、private作用范围</strong></h2><p>public：表示所有其他类都可以访问。</p>
<p>protected：当前类或子类可以访问，同时相同包内的其他类也可以访问protected成员；</p>
<p>default :默认（没有修饰符）：表示本包内可以使用</p>
<p>private：表示的是在本类内可以使用；</p>
<img src="/wang-cheng/2022/03/26/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%BA%8C/%E8%AE%BF%E9%97%AE%E4%BF%AE%E9%A5%B0%E7%AC%A6.png" class title="访问修饰符">

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/25/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%B8%83/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/25/%E9%9D%A2%E8%AF%95%E9%A2%98-%E4%B8%83/" class="post-title-link" itemprop="url">面试题(七)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-25 10:39:52" itemprop="dateCreated datePublished" datetime="2022-03-25T10:39:52+08:00">2022-03-25</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-04 20:57:05" itemprop="dateModified" datetime="2022-05-04T20:57:05+08:00">2022-05-04</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h2 id="Java中的泛型是什么-使用泛型的好处是什么"><a href="#Java中的泛型是什么-使用泛型的好处是什么" class="headerlink" title="Java中的泛型是什么 ? 使用泛型的好处是什么?"></a><strong>Java中的泛型是什么 ? 使用泛型的好处是什么?</strong></h2><p>这是在各种Java泛型面试中，一开场你就会被问到的问题中的一个，主要集中在初级和中级面试中。那些拥有Java1.4或更早版本的开发背景的人都知道，在集合中存储对象并在使用前进行类型转换是多么的不方便。泛型防止了那种情况的发生。它提供了编译期的类型安全，确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。</p>
<h2 id="Java的泛型是如何工作的-什么是类型擦除"><a href="#Java的泛型是如何工作的-什么是类型擦除" class="headerlink" title="Java的泛型是如何工作的 ? 什么是类型擦除 ?"></a><strong>Java的泛型是如何工作的 ? 什么是类型擦除 ?</strong></h2><p>这是一道更好的泛型面试题。泛型是通过类型擦除来实现的，编译器在编译时擦除了所有类型相关的信息，所以在运行时不存在任何类型相关的信息。例如List<String>在运行时仅用一个List来表示。这样做的目的，是确保能和Java 5之前的版本开发二进制类库进行兼容。你无法在运行时访问到类型参数，因为编译器已经把泛型类型转换成了原始类型。根据你对这个泛型问题的回答情况，你会得到一些后续提问，比如为什么泛型是由类型擦除来实现的或者给你展示一些会导致编译器出错的错误泛型代码。请阅读我的Java中泛型是如何工作的来了解更多信息。</String></p>
<h2 id="什么是泛型中的限定通配符和非限定通配符"><a href="#什么是泛型中的限定通配符和非限定通配符" class="headerlink" title="什么是泛型中的限定通配符和非限定通配符 ?"></a><strong>什么是泛型中的限定通配符和非限定通配符 ?</strong></h2><p>这是另一个非常流行的Java泛型面试题。限定通配符对类型进行了限制。有两种限定通配符，一种是&lt;? extends T&gt;它通过确保类型必须是T的子类来设定类型的上界，另一种是&lt;? super T&gt;它通过确保类型必须是T的父类来设定类型的下界。泛型类型必须用限定内的类型来进行初始化，否则会导致编译错误。另一方面&lt;?&gt;表示了非限定通配符，因为&lt;?&gt;可以用任意类型来替代。更多信息请参阅我的文章泛型中限定通配符和非限定通配符之间的区别。</p>
<h2 id="List-lt-extends-T-gt-和List-lt-super-T-gt-之间有什么区别"><a href="#List-lt-extends-T-gt-和List-lt-super-T-gt-之间有什么区别" class="headerlink" title="List&lt;? extends T&gt;和List &lt;? super T&gt;之间有什么区别 ?"></a><strong>List&lt;? extends T&gt;和List &lt;? super T&gt;之间有什么区别 ?</strong></h2><p>这和上一个面试题有联系，有时面试官会用这个问题来评估你对泛型的理解，而不是直接问你什么是限定通配符和非限定通配符。这两个List的声明都是限定通配符的例子，List&lt;? extends T&gt;可以接受任何继承自T的类型的List，而List&lt;? super T&gt;可以接受任何T的父类构成的List。例如List&lt;? extends Number&gt;可以接受List<Integer>或List<Float>。在本段出现的连接中可以找到更多信息。</Float></Integer></p>
<h2 id="如何编写一个泛型方法，让它能接受泛型参数并返回泛型类型"><a href="#如何编写一个泛型方法，让它能接受泛型参数并返回泛型类型" class="headerlink" title="如何编写一个泛型方法，让它能接受泛型参数并返回泛型类型?"></a><strong>如何编写一个泛型方法，让它能接受泛型参数并返回泛型类型?</strong></h2><p>编写泛型方法并不困难，你需要用泛型类型来替代原始类型，比如使用T, E or K,V等被广泛认可的类型占位符。泛型方法的例子请参阅Java集合类框架。最简单的情况下，一个泛型方法可能会像这样:<br><figure class="highlight maxima"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">public V <span class="built_in">put</span>(K <span class="built_in">key</span>, V value) &#123;</span><br><span class="line">    <span class="built_in">return</span> cache.<span class="built_in">put</span>(<span class="built_in">key</span>, value);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="Java中如何使用泛型编写带有参数的类"><a href="#Java中如何使用泛型编写带有参数的类" class="headerlink" title="Java中如何使用泛型编写带有参数的类?"></a><strong>Java中如何使用泛型编写带有参数的类?</strong></h2><p>这是上一道面试题的延伸。面试官可能会要求你用泛型编写一个类型安全的类，而不是编写一个泛型方法。关键仍然是使用泛型类型来代替原始类型，而且要使用JDK中采用的标准占位符。</p>
<h2 id="编写一段泛型程序来实现LRU缓存"><a href="#编写一段泛型程序来实现LRU缓存" class="headerlink" title="编写一段泛型程序来实现LRU缓存?"></a><strong>编写一段泛型程序来实现LRU缓存?</strong></h2><p>对于喜欢Java编程的人来说这相当于是一次练习。给你个提示，LinkedHashMap可以用来实现固定大小的LRU缓存，当LRU缓存已经满了的时候，它会把最老的键值对移出缓存。LinkedHashMap提供了一个称为removeEldestEntry()的方法，该方法会被put()和putAll()调用来删除最老的键值对。当然，如果你已经编写了一个可运行的JUnit测试，你也可以随意编写你自己的实现代码。</p>
<h2 id="你可以把List-lt-String-gt-传递给一个接受List-lt-Object-gt-参数的方法吗？"><a href="#你可以把List-lt-String-gt-传递给一个接受List-lt-Object-gt-参数的方法吗？" class="headerlink" title="你可以把List&lt;String&gt;传递给一个接受List&lt;Object&gt;参数的方法吗？"></a><strong>你可以把<code>List&lt;String&gt;</code>传递给一个接受<code>List&lt;Object&gt;</code>参数的方法吗？</strong></h2><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">List&lt;Object&gt; objectList<span class="comment">;</span></span><br><span class="line">List&lt;String&gt; stringList<span class="comment">;</span></span><br><span class="line"><span class="attribute">objectList</span> <span class="operator">=</span> stringList<span class="comment">;  //compilation error incompatible types</span></span><br></pre></td></tr></table></figure>
<h2 id="Array中可以用泛型吗"><a href="#Array中可以用泛型吗" class="headerlink" title="Array中可以用泛型吗?"></a><strong>Array中可以用泛型吗?</strong></h2><p>这可能是Java泛型面试题中最简单的一个了，当然前提是你要知道Array事实上并不支持泛型，这也是为什么Joshua Bloch在Effective Java一书中建议使用List来代替Array，因为List可以提供编译期的类型安全保证，而Array却不能。</p>
<h2 id="如何阻止Java中的类型未检查的警告"><a href="#如何阻止Java中的类型未检查的警告" class="headerlink" title="如何阻止Java中的类型未检查的警告?"></a><strong>如何阻止Java中的类型未检查的警告?</strong></h2><p>如果你把泛型和原始类型混合起来使用，例如下列代码，Java 5的javac编译器会产生类型未检查的警告，例如<br><figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">List&lt;<span class="keyword">String</span>&gt; rawList = <span class="keyword">new</span> <span class="type">ArrayList</span>()</span><br></pre></td></tr></table></figure></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/23/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%B8%80/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/23/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%B8%80/" class="post-title-link" itemprop="url">做题笔记(一)</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-23 16:26:18" itemprop="dateCreated datePublished" datetime="2022-03-23T16:26:18+08:00">2022-03-23</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-13 16:06:02" itemprop="dateModified" datetime="2022-05-13T16:06:02+08:00">2022-05-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="牛客网刷题笔记"><a href="#牛客网刷题笔记" class="headerlink" title="牛客网刷题笔记"></a><strong>牛客网刷题笔记</strong></h1><h2 id="数据库优化问题"><a href="#数据库优化问题" class="headerlink" title="数据库优化问题"></a><strong>数据库优化问题</strong></h2><p>主键会添加索引， 定长字段有利于查询优化， 将大数据量字段单独放在一个表中可以优化数据库表的存储性能</p>
<h2 id="floor、ceil函数问题"><a href="#floor、ceil函数问题" class="headerlink" title="floor、ceil函数问题"></a><strong>floor、ceil函数问题</strong></h2><figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;   </span><br><span class="line">   <span class="function"><span class="keyword">public</span> <span class="type">static</span> <span class="type">void</span> <span class="title">main</span><span class="params">(<span class="type">String</span>[] args)</span> </span>&#123;   </span><br><span class="line">     <span class="type">double</span>[] nums = &#123;<span class="number">-1.6</span>&#125;;   </span><br><span class="line">     <span class="keyword">for</span> (<span class="type">double</span> num : nums) &#123;   </span><br><span class="line">       <span class="built_in">test</span>(num);   </span><br><span class="line">     &#125;   </span><br><span class="line">   &#125;    </span><br><span class="line">   <span class="function"><span class="keyword">private</span> <span class="type">static</span> <span class="type">void</span> <span class="title">test</span><span class="params">(<span class="type">double</span> num)</span> </span>&#123;   </span><br><span class="line">     System.out.<span class="built_in">println</span>(Math.<span class="built_in">floor</span>(num));   <span class="comment">//-2.0</span></span><br><span class="line">     System.out.<span class="built_in">println</span>(Math.<span class="built_in">ceil</span>(num));   <span class="comment">//-1.0</span></span><br><span class="line">   &#125;   </span><br><span class="line"> &#125;</span><br></pre></td></tr></table></figure>
<p>floor：地板    ——&gt;    向下取整<br>ceil：天花板  ——&gt;    向上取整<br>由于 double 类型，小数点依旧存在</p>
<h2 id="同步锁机制"><a href="#同步锁机制" class="headerlink" title="同步锁机制"></a><strong>同步锁机制</strong></h2><p>在java中，每个对象只能获得一个同步锁</p>
<h2 id="设计模式类问题"><a href="#设计模式类问题" class="headerlink" title="设计模式类问题"></a><strong>设计模式类问题</strong></h2><p>适配器型属于结构型模式</p>
<p>创建型：对象的创建；</p>
<p>结构型：对象的组成；</p>
<p>行为型：对象的功能</p>
<h2 id="数据库引擎类问题"><a href="#数据库引擎类问题" class="headerlink" title="数据库引擎类问题"></a><strong>数据库引擎类问题</strong></h2><p>MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的。要添加一个新的引擎，就必须重新编译MYSQL。在缺省情况下，MYSQL支持三个引擎：<code>ISAM</code>、<code>MYISAM</code>和<code>HEAP</code>。另外两种类型INNODB和BERKLEY（BDB），也常常可以使用。如果技术高超，还可以使用MySQL++ API自己做一个引擎。</p>
<p><code>ISAM</code>：<code>ISAM</code>是一个定义明确且历经时间考验的数据表格管理方法，它在设计之时就考虑到数据库被查询的次数要远大于更新的次数。因此，<code>ISAM</code>执行读取操作的速度很快，而且不占用大量的内存和存储资源。<code>ISAM</code>的两个主要不足之处在于，它不支持事务处理，也不能够容错：如果你的硬盘崩溃了，那么数据文件就无法恢复了。如果你正在把<code>ISAM</code>用在关键任务应用程序里，那就必须经常备份你所有的实时数据，通过其复制特性，MYSQL能够支持这样的备份应用程序。</p>
<p><code>MyISAM</code>：<code>MyISAM</code>是MySQL的ISAM扩展格式和缺省的数据库引擎。除了提供ISAM里所没有的索引和字段管理的大量功能，<code>MyISAM</code>还使用一种表格锁定的机制，来优化多个并发的读写操作，其代价是你需要经常运行OPTIMIZE TABLE命令，来恢复被更新机制所浪费的空间。<code>MyISAM</code>还有一些有用的扩展，例如用来修复数据库文件的MyISAMCHK工具和用来恢复浪费空间的 MyISAMPACK工具。<code>MYISAM</code>强调了快速读取操作，这可能就是为什么MySQL受到了WEB开发如此青睐的主要原因：在WEB开发中你所进行的大量数据操作都是读取操作。所以，大多数虚拟主机提供商和INTERNET平台提供商只允许使用<code>MYISAM</code>格式。<code>MyISAM</code>格式的一个重要缺陷就是不能在表损坏后恢复数据。</p>
<p><code>HEAP</code>：<code>HEAP</code>允许只驻留在内存里的临时表格。驻留在内存里让<code>HEAP</code>要比<code>ISAM</code>和<code>MYISAM</code>都快，但是它所管理的数据是不稳定的，而且如果在关机之前没有进行保存，那么所有的数据都会丢失。在数据行被删除的时候，<code>HEAP</code>也不会浪费大量的空间。<code>HEAP</code>表格在你需要使用SELECT表达式来选择和操控数据的时候非常有用。要记住，在用完表格之后就删除表格。</p>
<p><code>InnoDB</code>：<code>InnoDB</code>数据库引擎都是造就MySQL灵活性的技术的直接产品，这项技术就是MYSQL++ API。在使用MYSQL的时候，你所面对的每一个挑战几乎都源于<code>ISAM</code>和<code>MyISAM</code>数据库引擎不支持事务处理（transaction process）也不支持外来键。尽管要比<code>ISAM</code>和 <code>MyISAM</code>引擎慢很多，但是<code>InnoDB</code>包括了对事务处理和外来键的支持，这两点都是前两个引擎所没有的。如前所述，如果你的设计需要这些特性中的一者 或者两者，那你就要被迫使用后两个引擎中的一个了。</p>
<p>MySQL 官方对<code>InnoDB</code>是这样解释的：<code>InnoDB</code>给MySQL提供了具有提交、回滚和崩溃恢复能力的事务安全（ACID兼容）存储引擎。InnoDB锁定在行级并且也在SELECT语句提供一个Oracle风格一致的非锁定读，这些特色增加了多用户部署和性能。没有在<code>InnoDB</code>中扩大锁定的需要，因为在InnoDB中行级锁定适合非常小的空间。<code>InnoDB</code>也支持FOREIGN KEY强制。在SQL查询中，你可以自由地将<code>InnoDB</code>类型的表与其它MySQL的表的类型混合起来，甚至在同一个查询中也可以混合。</p>
<p><code>InnoDB</code>是为处理巨大数据量时的最大性能设计，它的CPU效率可能是任何其它基于磁盘的关系数据库引擎所不能匹敌的。</p>
<p><code>InnoDB</code>存储引擎被完全与MySQL服务器整合，<code>InnoDB</code>存储引擎为在主内存中缓存数据和索引而维持它自己的缓冲池。<code>InnoDB</code>存储它的表＆索引在一个表空间中，表空间可以包含数个文件（或原始磁盘分区）。这与<code>MyISAM</code>表不同，比如在<code>MyISAM</code>表中每个表被存在分离的文件中。<code>InnoDB</code> 表可以是任何尺寸，即使在文件尺寸被限制为2GB的操作系统上。<code>InnoDB</code>默认地被包含在MySQL二进制分发中。Windows Essentials installer使<code>InnoDB</code>成为Windows上MySQL的默认表。<code>InnoDB</code>被用来在众多需要高性能的大型数据库站点上产生。著名的Internet新闻站点Slashdot.org运行在<code>InnoDB</code>上。 Mytrix, Inc.在<code>InnoDB</code>上存储超过1TB的数据，还有一些其它站点在<code>InnoDB</code>上处理平均每秒800次插入/更新的</p>
<p>一般来说，<code>MyISAM</code>适合：(1)做很多count 的计算；(2)插入不频繁，查询非常频繁；(3)没有事务。<code>InnoDB</code>适合：(1)可靠性要求比较高，或者要求事务；(2)表更新和查询都相当的频繁，并且表锁定的机会比较大的情况</p>
<h2 id="SQL中limit用法"><a href="#SQL中limit用法" class="headerlink" title="SQL中limit用法"></a><strong>SQL中limit用法</strong></h2><figure class="highlight n1ql"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> * <span class="keyword">from</span> tableName <span class="keyword">limit</span> i,n</span><br></pre></td></tr></table></figure>
<p>tableName : 为数据表；<br>i : 为查询结果的索引值（默认从0开始）；<br>n : 为查询结果返回的数量</p>
<figure class="highlight axapta"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">select</span> * <span class="keyword">from</span> student limit <span class="number">1</span> <span class="comment">//查询第一条数据</span></span><br></pre></td></tr></table></figure>
<h2 id="完全二叉树"><a href="#完全二叉树" class="headerlink" title="完全二叉树"></a><strong>完全二叉树</strong></h2><p>一棵深度为k的有n个结点的二叉树，对树中的结点按从上至下、从左到右的顺序进行编号，如果编号为i（1≤i≤n）的结点与满二叉树中编号为i的结点在二叉树中的位置相同，则这棵二叉树称为完全二叉树。</p>
<img src="/wang-cheng/2022/03/23/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%B8%80/%E5%AE%8C%E5%85%A8%E4%BA%8C%E5%8F%89%E6%A0%91.jpg" class title="完全二叉树">
<h2 id="堆排序"><a href="#堆排序" class="headerlink" title="堆排序"></a><strong>堆排序</strong></h2><p>堆：n个元素的序列{k1,k2…,kn}，当且仅当满足下列关系时，称之为堆。</p>
<script type="math/tex; mode=display">
  \begin{Bmatrix}
    ki <= k2i \\
    ki <= k2i+1 \\
   \end{Bmatrix}</script><p>或者</p>
<script type="math/tex; mode=display">
  \begin{Bmatrix}
    ki >= k2i \\
    ki >= k2i+1 \\
   \end{Bmatrix}</script><ol>
<li><p>最小(大)堆的排序规则:将根节点(最小(大)值)摘除堆，并将最后一个节点放置到根节点</p>
</li>
<li><p>随后进行堆的检查，如果不符合最小(大)堆，则将不符合的最小(大)子节点与之交换，然后重复第二步，直到符合最小(大)堆</p>
</li>
<li><p>重复第一步，直到节点全部摘除</p>
</li>
</ol>
<h2 id="二叉树转堆"><a href="#二叉树转堆" class="headerlink" title="二叉树转堆"></a><strong>二叉树转堆</strong></h2><p>二叉树转最大(小)堆的的规则：</p>
<ol>
<li><p>首先自下而上、自右向左依次开始检查节点是否符合规则。如果不符合，则将其与最大(小)的叶子节点进行交换</p>
</li>
<li><p>检查被交换后的节点是否符合最大(小)堆，如果不符合，则继续进行交换 </p>
</li>
<li><p>交换后继续向左检查节点是否符合最大(小)堆，如果当前层检查完毕，则向上检查，从最右节点开始。</p>
</li>
<li><p>直到检查到根节点，至此，转换结束。</p>
</li>
</ol>
<h2 id="快速排序算法"><a href="#快速排序算法" class="headerlink" title="快速排序算法"></a><strong>快速排序算法</strong></h2><ol>
<li><p>选定Pivot中心轴(任意一个数字)</p>
</li>
<li><p>将大于Pivot的数字放在Pivot的右边</p>
</li>
<li><p>将小于Pivot的数字放在Pivot的左边</p>
</li>
<li><p>分别对左右子序列重复前三步操作</p>
</li>
</ol>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">int</span> <span class="constructor">Partition(SqList &amp;L,<span class="params">int</span> <span class="params">low</span>, <span class="params">int</span> <span class="params">high</span>)</span>&#123;</span><br><span class="line">  <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="number">0</span>]</span> = <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">row</span>]</span>;                                          <span class="comment">//用子表的第一个记录作枢轴记录</span></span><br><span class="line">  privotekey = <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">low</span>]</span>.key;                                  <span class="comment">//枢轴记录关键字</span></span><br><span class="line">  <span class="keyword">while</span>(low &lt; high)&#123;                                          <span class="comment">//从表的两端交替地向中间扫描</span></span><br><span class="line">    <span class="keyword">while</span>(low &lt; high<span class="operator"> &amp;&amp; </span><span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">high</span>]</span>.key &gt;= pivotekey) --high;</span><br><span class="line">    <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">row</span>]</span> = <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">high</span>]</span>;                                     <span class="comment">//将比枢轴记录小的记录移到低端</span></span><br><span class="line">    <span class="keyword">while</span>(low &lt; high<span class="operator"> &amp;&amp; </span><span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">low</span>]</span>.key &lt;= privotekey) ++low;</span><br><span class="line">    <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">high</span>]</span> = <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">low</span>]</span>;                                     <span class="comment">//将比枢轴记录大的记录移到高端</span></span><br><span class="line">  &#125;</span><br><span class="line">  <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="identifier">low</span>]</span> = <span class="module-access"><span class="module"><span class="identifier">L</span>.</span></span>r<span class="literal">[<span class="number">0</span>]</span>;                                          <span class="comment">//枢轴记录到位</span></span><br><span class="line">  return low;                                                 <span class="comment">//返回枢轴位置</span></span><br><span class="line">&#125;<span class="comment">//Partition</span></span><br></pre></td></tr></table></figure>
<h2 id="static"><a href="#static" class="headerlink" title="static"></a><strong>static</strong></h2><ol>
<li><p>静态变量</p>
<ul>
<li>静态变量：又称为类变量，也就是说这个变量属于类的，类所有的实例都共享静态变量，可以直接通过类名来访问它；静态变量在内存中只存在一份。</li>
<li>实例变量：每创建一个实例就会产生一个实例变量，它与该实例同生共死。</li>
</ul>
</li>
</ol>
<figure class="highlight arduino"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">A</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="type">int</span> x;         <span class="comment">// 实例变量</span></span><br><span class="line">    <span class="keyword">private</span> <span class="type">static</span> <span class="type">int</span> y;  <span class="comment">// 静态变量</span></span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="type">static</span> <span class="type">void</span> <span class="title">main</span><span class="params">(<span class="type">String</span>[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">// int x = A.x;  // Non-static field &#x27;x&#x27; cannot be referenced from a static context</span></span><br><span class="line">        A a = <span class="keyword">new</span> <span class="built_in">A</span>();</span><br><span class="line">        <span class="type">int</span> x = a.x;</span><br><span class="line">        <span class="type">int</span> y = A.y;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<ol>
<li>静态方法</li>
</ol>
<p>静态方法在类加载的时候就存在了，它不依赖于任何实例。所以静态方法必须有实现，也就是说它不能是抽象方法（abstract）。<br><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title">A</span> &#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">func1</span>()</span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">// public abstract static void func2();  // Illegal combination of modifiers: &#x27;abstract&#x27; and &#x27;static&#x27;</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">//也就是说abstract和static不能修饰同一个方法</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<p>只能访问所属类的静态字段和静态方法，方法中不能有 this 和 super 关键字。<br><figure class="highlight csharp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title">A</span> &#123;</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="built_in">int</span> x;</span><br><span class="line">    <span class="keyword">private</span> <span class="built_in">int</span> y;</span><br><span class="line"> </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">func1</span>()</span>&#123;</span><br><span class="line">        <span class="built_in">int</span> a = x;</span><br><span class="line">        <span class="comment">// int b = y;  // Non-static field &#x27;y&#x27; cannot be referenced from a static context</span></span><br><span class="line">        <span class="comment">// int b = this.y;     // &#x27;A.this&#x27; cannot be referenced from a static context</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<ol>
<li>静态语句块</li>
</ol>
<p>静态语句块在类初始化时运行一次</p>
<ol>
<li>静态内部类</li>
</ol>
<p>非静态内部类依赖于外部类的实例，而静态内部类不需要。</p>
<figure class="highlight haxe"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">OuterClass</span> </span>&#123;</span><br><span class="line">    <span class="class"><span class="keyword">class</span> <span class="title">InnerClass</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">StaticInnerClass</span> </span>&#123;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> void main(<span class="keyword">String</span>[] args) &#123;</span><br><span class="line">        <span class="comment">// InnerClass innerClass = new InnerClass(); // &#x27;OuterClass.this&#x27; cannot be referenced from a static context</span></span><br><span class="line">        OuterClass outerClass = <span class="keyword">new</span> <span class="type">OuterClass</span>();</span><br><span class="line">        InnerClass innerClass = outerClass.<span class="keyword">new</span> <span class="type">InnerClass</span>();</span><br><span class="line">        StaticInnerClass staticInnerClass = <span class="keyword">new</span> <span class="type">StaticInnerClass</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>静态内部类不能访问外部类的非静态的变量和方法。</p>
<h2 id="TCP与UDP"><a href="#TCP与UDP" class="headerlink" title="TCP与UDP"></a><strong>TCP与UDP</strong></h2><p>TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。</p>
<p>其中TCP提供IP环境下的数据可靠传输，它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复用。通过面向连接、端到端和可靠的数据包发送。通俗说，它是事先为所发送的数据开辟出连接好的通道，然后再进行数据发送；一般来说，TCP对应的是可靠性要求高的应用。</p>
<p>而UDP则不为IP提供可靠性、流控或差错恢复功能。UDP对应的则是可靠性要求低、传输经济的应用。</p>
<p>TCP支持的应用协议主要有：Telnet、FTP、SMTP等；</p>
<p><strong>TCP对应的协议</strong></p>
<ul>
<li><p>FTP：定义了文件传输协议，使用21端口。</p>
</li>
<li><p>Telnet：一种用于远程登陆的端口，使用23端口，用户可以以自己的身份远程连接到计算机上，可提供基于DOS模式下的通信服务。</p>
</li>
<li><p>SMTP：邮件传送协议，用于发送邮件。服务器开放的是25号端口。</p>
</li>
<li><p>POP3：它是和SMTP对应，POP3用于接收邮件。POP3协议所用的是110端口。</p>
</li>
<li><p>HTTP：是从Web服务器传输超文本到本地浏览器的传送协议。</p>
</li>
</ul>
<p><strong>UDP对应的协议</strong></p>
<ul>
<li><p>DNS：用于域名解析服务，将域名地址转换为IP地址。DNS用的是53号端口。</p>
</li>
<li><p>SNMP：简单网络管理协议，使用161号端口，是用来管理网络设备的。由于网络设备很多，无连接的服务就体现出其优势。</p>
</li>
<li><p>TFTP(Trival File transport Protocal)，简单文件传输协议，该协议在熟知端口69上使用UDP服务。</p>
</li>
</ul>
<img src="/wang-cheng/2022/03/23/%E5%81%9A%E9%A2%98%E7%AC%94%E8%AE%B0-%E4%B8%80/TCP%E4%B8%8EUDP.png" class title="TCP与UDP">
<h2 id="有一条TCP连接，它的最大报文段长度为4KB，TCP拥塞窗口为24KB，这时候发生超时，那么该拥塞窗口变为了"><a href="#有一条TCP连接，它的最大报文段长度为4KB，TCP拥塞窗口为24KB，这时候发生超时，那么该拥塞窗口变为了" class="headerlink" title="有一条TCP连接，它的最大报文段长度为4KB，TCP拥塞窗口为24KB，这时候发生超时，那么该拥塞窗口变为了"></a><strong>有一条TCP连接，它的最大报文段长度为4KB，TCP拥塞窗口为24KB，这时候发生超时，那么该拥塞窗口变为了</strong></h2><p>TCP报文中，当发生超时事件，阈值被设置成当前拥塞窗口的一半，而拥塞窗口被设为一个最大报文段，也就是4KB。</p>
<p>实际上，慢开始、拥塞避免算法、快重传和快恢复几种算法应该是同时应用在拥塞控制中的，当发送方检测到超时的时候就采用慢开始和拥塞避免，当发送方接收到冗余ACK时就采用快重传和快恢复。因此超时应采用慢开始拥塞避免算法，拥塞窗口的值被设为1个单位；即拥塞窗口的大小为1*4KB=4KB。</p>
<h2 id="线程同步问题"><a href="#线程同步问题" class="headerlink" title="线程同步问题"></a><strong>线程同步问题</strong></h2><p>临界区（Critical Section）：适合一个进程内的多线程访问公共区域或代码段时使用(临界区只能用于单个进程内多线程的同步)</p>
<p>互斥量 (Mutex)：适合不同进程内多线程访问公共区域或代码段时使用，与临界区相似(互斥量还能用于多个进程间多线程的同步)</p>
<p>事件（Event）：通过线程间触发事件实现同步互斥。</p>
<p>信号量（Semaphore）：与临界区和互斥量不同，可以实现多个线程同时访问公共区域数据，原理与操作系统中PV操作类似，先设置一个访问公共区域的线程最大连接数，每有一个线程访问共享区资源数就减一，直到资源数小于等于零。</p>
<h2 id="死锁解决时机"><a href="#死锁解决时机" class="headerlink" title="死锁解决时机"></a><strong>死锁解决时机</strong></h2><p>按照死锁解决时机的不同分为，预防死锁、避免死锁、检测并解除死锁三个阶段</p>
<p>银行家算法是用在避免死锁阶段的。</p>
<h2 id="矩阵相乘"><a href="#矩阵相乘" class="headerlink" title="矩阵相乘"></a><strong>矩阵相乘</strong></h2><p>根据矩阵相乘的原理得知，m1<em>n的矩阵和n</em>m2的矩阵相乘， 需要做m1<em>n</em>m2次乘法运算，因此需要优先计算n更大的矩阵，这样会最大地减少乘法运算的次数</p>
<h2 id="不可能是快速排序第2趟排序结果问题"><a href="#不可能是快速排序第2趟排序结果问题" class="headerlink" title="不可能是快速排序第2趟排序结果问题"></a><strong>不可能是快速排序第2趟排序结果问题</strong></h2><p>每趟排序就有一个元素排在了最终的位置上。那么就是说，第n趟结束，<strong>至少</strong>有n个元素已经排在了最终的位置上。</p>
<p>所以我们把最终排序结果写出来：然后计算在最终位置上的个数就可以</p>
<h2 id="Vector-ArrayList-LinkedList的不同场景下的性能差别"><a href="#Vector-ArrayList-LinkedList的不同场景下的性能差别" class="headerlink" title="Vector, ArrayList, LinkedList的不同场景下的性能差别"></a><strong>Vector, ArrayList, LinkedList的不同场景下的性能差别</strong></h2><p>LinkedList是一个双向链表结构.线程不安全.适合于中间部位添加和删除.初始值是16，然后扩容1.5倍</p>
<p>ArrayList 是一个数组结构.线程不安全.适合于查询和修改，以及尾部的添加和删除. </p>
<p>Vector 是一个数组结构。但是关键的添加，删除等方法都已经用synchronized修饰，是线程安全的.适合于查询，以及尾部的添加和删除.扩容方式为2倍</p>
<h2 id="通讯中阻塞（blocking）-非阻塞（non-blocking-与-同步-异步IO的区别"><a href="#通讯中阻塞（blocking）-非阻塞（non-blocking-与-同步-异步IO的区别" class="headerlink" title="通讯中阻塞（blocking）/非阻塞（non-blocking 与 同步/异步IO的区别"></a><strong>通讯中阻塞（blocking）/非阻塞（non-blocking 与 同步/异步IO的区别</strong></h2><p>同步／异步主要针对客户端：</p>
<ul>
<li><p>同步：就是当客户端发出一个功能调用时，在没有得到结果之前，该调用就不返回。也就是说必须一件一件的事情去做，等一件做完了才能去做下一件。</p>
</li>
<li><p>异步：就是当客户端发出一个功能调用时，调用者不用等接收方发出响应。实际处理这个调用的部件在完成后，会通过状态，通知和回调来通知调用者。客户端可以接着去做 后面的事情。</p>
</li>
</ul>
<p>虽然主要是针对客户端，但是服务器端不是完全没有关系的，同步／异步必须配合服务器端才能实现。同步／异步是由客户端自己控制，但是服务器端是否阻塞/非阻塞，客户端完全不需要关心。</p>
<p>阻塞／非阻塞主要是针对服务器端：</p>
<ul>
<li><p>阻塞：阻塞调用是指服务器端被调用者调用结果返回之前，当前线程会被挂起。调用线程只有在得到结果之后才会返回。</p>
</li>
<li><p>非阻塞：指在不能立即得到结果之前，该调用不会阻塞当前线程。</p>
</li>
</ul>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/23/JVM%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/23/JVM%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" class="post-title-link" itemprop="url">JVM学习笔记</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-23 11:59:47" itemprop="dateCreated datePublished" datetime="2022-03-23T11:59:47+08:00">2022-03-23</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-05-13 11:18:50" itemprop="dateModified" datetime="2022-05-13T11:18:50+08:00">2022-05-13</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a><strong>JVM</strong></h1><h2 id="沙箱安全机制"><a href="#沙箱安全机制" class="headerlink" title="沙箱安全机制"></a><strong>沙箱安全机制</strong></h2><ul>
<li><p>字节码校验器：确保Java类文件遵循Java语言规范。这样可以帮助Java程序实现内存保护。但并不是所有的类文件都会经过字节码校验，例如核心类。</p>
</li>
<li><p>类装载器：其中类装载器在3个方面堆Java沙箱起作用</p>
<ul>
<li><p>它防止恶意代码去干涉善意代码  //双亲委派机制</p>
</li>
<li><p>它守护了被信任的类库边界</p>
</li>
<li><p>它将代码归入保护域，确定了代码可以进行哪些操作</p>
</li>
</ul>
</li>
</ul>
<p>虚拟机为不同的类加载器载入的类提供不同的命名空间，命名空间由一系列唯一的名称组成，每一个被装载的类将有一个名字，这个命名空间是由Java虚拟机为每一个类装载器维护的，它们互相之间甚至看不见</p>
<p>类加载器采用的机制是双亲委派机制</p>
<ol>
<li><p>从最内存JVM自带类加载器开始加载，外层恶意同名类得不到加载从而无法使用</p>
</li>
<li><p>由于严格通过包来区分了访问域，外部恶意的类通过内置代码也无法获得权限访问到内层类，破坏代码就自然无法生效</p>
</li>
</ol>
<ul>
<li><p>存取控制器：存取控制器可以控制核心API对操作系统的存取权限，而这个控制的策略设定，可以由用户指定</p>
</li>
<li><p>安全管理器：是核心API和操作系统之间的主要接口。实现权限控制，比存取控制器优先级高</p>
</li>
<li><p>安全软件包：java.security下的类和扩展包下的类，允许用户为自己的应用增加新的安全特性，包括：</p>
<ul>
<li><p>安全提供者</p>
</li>
<li><p>消息摘要</p>
</li>
<li><p>数字签名</p>
</li>
<li><p>加密</p>
</li>
<li><p>鉴别</p>
</li>
</ul>
</li>
</ul>
<h2 id="Native、方法区"><a href="#Native、方法区" class="headerlink" title="Native、方法区"></a><strong>Native、方法区</strong></h2><p>native：凡是带了native关键字的，说明java的作用范围达不到了，会去调用底层C语言的库</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">private</span> <span class="keyword">native</span> <span class="function"><span class="keyword">void</span> <span class="title">start0</span><span class="params">()</span></span>;</span><br></pre></td></tr></table></figure>
<ul>
<li><p>会进入本地方法栈</p>
</li>
<li><p>本地方法栈会调用本地方法接口(JNI (java native interface) )</p>
<ul>
<li>JNI的作用：扩展Java的使用，融合不同的编程语言为Java所用！  最初是想调用C、C++</li>
<li>它在内存区域中专门开辟了一块标记区域(本地方法栈)，登记native方法</li>
<li>在最终执行的时候，去加载本地方法库中的方法，通过JNI</li>
</ul>
</li>
<li>本地方法接口会调用本地方法库</li>
</ul>
<h2 id="PC寄存器"><a href="#PC寄存器" class="headerlink" title="PC寄存器"></a><strong>PC寄存器</strong></h2><p>程序计数器:Program Counter Register</p>
<p>每一个线程都有一个程序计数器，是线程私有的，就是一个指针，指向方法区中的方法字节码(用来存储指向一条指令的地址，也即将要执行的指令代码)，在执行引擎读取下一条指令，是一个非常小的内存空间，几乎可以忽略不计。</p>
<h2 id="方法区"><a href="#方法区" class="headerlink" title="方法区"></a><strong>方法区</strong></h2><p>Method Area 方法区</p>
<p>方法区是被所有线程共享，所有字段和方法字节码，以及一些特殊方法，如构造函数，接口代码也在此定义，简单说，所有定义的方法的信息都保存在该区域，<strong>此区域属于共享区间</strong></p>
<p><code>静态变量、常量、类信息(构造方法、接口定义)、运行时的常量池存在方法区中，但是实例变量存在堆内存中，和方法区无关</code></p>
<h2 id="GC-垃圾回收机制"><a href="#GC-垃圾回收机制" class="headerlink" title="GC:垃圾回收机制"></a><strong>GC:垃圾回收机制</strong></h2><p>GC的作用区只有方法区和堆，也就是说只对这两块起作用</p>
<p>JVM在进行GC时，并不是对这三个区域统一回收，大部分时候，回收都是新生代</p>
<ul>
<li>新生代</li>
<li>幸存区</li>
<li>老年区</li>
</ul>
<p>GC分两类:轻GC、重GC(全局GC)</p>
<p>轻GC主要针对新生代，偶尔针对幸存区</p>
<p>重GC把三个区都清一遍</p>
<p>GC题目：</p>
<p>堆里面的分区有哪些？</p>
<pre><code>Eden，from,to,老年区，说说他们的特点
</code></pre><p>GC的算法有哪些？</p>
<pre><code>标记清除法，标记压缩，复制算法，引用计数器。怎么用的。
</code></pre><h2 id="JVM内存屏障"><a href="#JVM内存屏障" class="headerlink" title="JVM内存屏障"></a><strong>JVM内存屏障</strong></h2><p><strong>Load是读，Store是写</strong></p>
<p>LoadLoad屏障：</p>
<p>对于这样的语句Load1,LoadLoad,Load2,在Load2及后续读取操作要读取的数据被访问前，保证Load1要读取的数据被读取完毕</p>
<p>StoreStore屏障：</p>
<p>对于这样的语句Store1,StoreStore,Store2,在Store2及后续写入操作执行前，保证Store的写入操作对其他处理器可见</p>
<p>LoadStore屏障：</p>
<p>对于这样的语句Load1,LoadStore,Store2,在Store2及后续写入操作被刷出前，保证Load1要读取的数据被读取完毕</p>
<p>StoreLoad屏障:</p>
<p>对于这样的语句Store1,StoreLoad,Load2,在Load2及后续所有读取操作执行前，保证Store1的写入对所有处理器可见</p>
<p><a target="_blank" rel="noopener" href="https://blog.csdn.net/qq_35091353/article/details/116354734">https://blog.csdn.net/qq_35091353/article/details/116354734</a></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  


  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/wang-cheng/"><i class="fa fa-angle-left" aria-label="上一页"></i></a><a class="page-number" href="/wang-cheng/">1</a><span class="page-number current">2</span><a class="page-number" href="/wang-cheng/page/3/">3</a><a class="page-number" href="/wang-cheng/page/4/">4</a><a class="extend next" rel="next" href="/wang-cheng/page/3/"><i class="fa fa-angle-right" aria-label="下一页"></i></a>
  </nav>



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">王诚</p>
  <div class="site-description" itemprop="description">命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/wang-cheng/archives/">
        
          <span class="site-state-item-count">32</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/wang-cheng/tags/">
          
        <span class="site-state-item-count">12</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">王诚</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/wang-cheng/lib/anime.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.ui.min.js"></script>

<script src="/wang-cheng/js/utils.js"></script>

<script src="/wang-cheng/js/motion.js"></script>


<script src="/wang-cheng/js/schemes/pisces.js"></script>


<script src="/wang-cheng/js/next-boot.js"></script>




  















  

  
      

<script>
  if (typeof MathJax === 'undefined') {
    window.MathJax = {
      loader: {
        source: {
          '[tex]/amsCd': '[tex]/amscd',
          '[tex]/AMScd': '[tex]/amscd'
        }
      },
      tex: {
        inlineMath: {'[+]': [['$', '$']]},
        tags: 'ams'
      },
      options: {
        renderActions: {
          findScript: [10, doc => {
            document.querySelectorAll('script[type^="math/tex"]').forEach(node => {
              const display = !!node.type.match(/; *mode=display/);
              const math = new doc.options.MathItem(node.textContent, doc.inputJax[0], display);
              const text = document.createTextNode('');
              node.parentNode.replaceChild(text, node);
              math.start = {node: text, delim: '', n: 0};
              math.end = {node: text, delim: '', n: 0};
              doc.math.push(math);
            });
          }, '', false],
          insertedScript: [200, () => {
            document.querySelectorAll('mjx-container').forEach(node => {
              let target = node.parentNode;
              if (target.nodeName.toLowerCase() === 'li') {
                target.parentNode.classList.add('has-jax');
              }
            });
          }, '', false]
        }
      }
    };
    (function () {
      var script = document.createElement('script');
      script.src = '//cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js';
      script.defer = true;
      document.head.appendChild(script);
    })();
  } else {
    MathJax.startup.document.state(0);
    MathJax.texReset();
    MathJax.typeset();
  }
</script>

    

  

</body>
</html>
